The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
Changes 013
MANIFEST 23
META.yml 22
Makefile.PL 56
inc/Module/AutoInstall.pm 215
inc/Module/Install/AuthorTests.pm 059
inc/Module/Install/AutoInstall.pm 11
inc/Module/Install/Base.pm 11
inc/Module/Install/Can.pm 11
inc/Module/Install/Fetch.pm 11
inc/Module/Install/Include.pm 11
inc/Module/Install/Makefile.pm 1455
inc/Module/Install/Metadata.pm 1741
inc/Module/Install/Win32.pm 11
inc/Module/Install/WriteAll.pm 11
inc/Module/Install.pm 1126
lib/Catalyst/Manual/Cookbook.pod 3336
lib/Catalyst/Manual/Intro.pod 11
lib/Catalyst/Manual/Tutorial/01_Intro.pod 28134
lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod 40104
lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod 157225
lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod 14592
lib/Catalyst/Manual/Tutorial/05_Authentication.pod 12998
lib/Catalyst/Manual/Tutorial/06_Authorization.pod 3020
lib/Catalyst/Manual/Tutorial/07_Debugging.pod 22
lib/Catalyst/Manual/Tutorial/08_Testing.pod 4219
lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod 2419
lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormHandler.pod 18
lib/Catalyst/Manual/Tutorial.pod 57
lib/Catalyst/Manual.pm 11
t/author/pod-coverage.t 05
t/author/pod.t 04
t/pod-coverage.t 70
t/pod.t 70
34 files changed (This is a version diff) 7121002
@@ -1,5 +1,18 @@
 Revision history for Catalyst-Manual
 
+5.8004 17 Feb 2010
+    - Tutorial:
+        - Add foreign key support for SQLite 
+            (huge thanks to Caelum for that and other good edits!)
+        - Add "Quick Start" to Intro (Chapter 1)
+        - Switch to use of "-r" to auto-restart the dev svr
+        - Update for latest available Debian package versions
+        - Switch to individual files for example code vs. tarballs
+        - Switch to 'done_testing' and shorter 'prove' args for testing chapter
+        - Misc typo fixes
+    - Other:
+        - Minor Cookbook edits
+
 5.8003 28 Dec 2009
     - Variety of typo fixes
     - Fix incorrectness re :Global and :Local
@@ -2,6 +2,7 @@ Changes
 inc/Module/AutoInstall.pm
 inc/Module/Install.pm
 inc/Module/Install/AuthorRequires.pm
+inc/Module/Install/AuthorTests.pm
 inc/Module/Install/AutoInstall.pm
 inc/Module/Install/Base.pm
 inc/Module/Install/Can.pm
@@ -42,6 +43,6 @@ MANIFEST			This list of files
 META.yml
 README
 t/01-use.t
-t/pod-coverage.t
-t/pod.t
+t/author/pod-coverage.t
+t/author/pod.t
 TODO
@@ -8,7 +8,7 @@ build_requires:
 configure_requires:
   ExtUtils::MakeMaker: 6.42
 distribution_type: module
-generated_by: 'Module::Install version 0.910'
+generated_by: 'Module::Install version 0.930'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -21,4 +21,4 @@ no_index:
 resources:
   license: http://dev.perl.org/licenses/
   repository: http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/
-version: 5.8003
+version: 5.8004
@@ -2,9 +2,8 @@ use strict;
 use warnings;
 use inc::Module::Install 0.87;
 
-if ($Module::Install::AUTHOR) {
-    require Module::Install::AuthorRequires;
-}
+use Module::Install::AuthorTests;
+use Module::Install::AuthorRequires;
 
 name 'Catalyst-Manual';
 all_from 'lib/Catalyst/Manual.pm';
@@ -13,8 +12,10 @@ license 'perl';
 
 test_requires 'Test::More';
 
-author_requires 'Test::Pod';
-author_requires 'Test::Pod::Coverage';
+author_requires 'Pod::Simple' => '3.11'; # L<Foo|http://foo.com> support
+author_requires 'Test::Pod' => '1.14';
+author_requires 'Test::Pod::Coverage' => '1.04';
+author_tests 't/author';
 
 auto_install;
 resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/';
@@ -672,7 +672,20 @@ sub _load {
 sub _load_cpan {
     return if $CPAN::VERSION and $CPAN::Config and not @_;
     require CPAN;
-    if ( $CPAN::HandleConfig::VERSION ) {
+
+    # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to
+    #    CPAN::HandleConfig->load. CPAN reports that the redirection
+    #    is deprecated in a warning printed at the user.
+
+    # CPAN-1.81 expects CPAN::HandleConfig->load, does not have
+    #   $CPAN::HandleConfig::VERSION but cannot handle
+    #   CPAN::Config->load
+
+    # Which "versions expect CPAN::Config->load?
+
+    if ( $CPAN::HandleConfig::VERSION
+        || CPAN::HandleConfig->can('load')
+    ) {
         # Newer versions of CPAN have a HandleConfig module
         CPAN::HandleConfig->load;
     } else {
@@ -802,4 +815,4 @@ END_MAKE
 
 __END__
 
-#line 1056
+#line 1069
@@ -0,0 +1,59 @@
+#line 1
+package Module::Install::AuthorTests;
+
+use 5.005;
+use strict;
+use Module::Install::Base;
+use Carp ();
+
+#line 16
+
+use vars qw{$VERSION $ISCORE @ISA};
+BEGIN {
+  $VERSION = '0.002';
+  $ISCORE  = 1;
+  @ISA     = qw{Module::Install::Base};
+}
+
+#line 42
+
+sub author_tests {
+  my ($self, @dirs) = @_;
+  _add_author_tests($self, \@dirs, 0);
+}
+
+#line 56
+
+sub recursive_author_tests {
+  my ($self, @dirs) = @_;
+  _add_author_tests($self, \@dirs, 1);
+}
+
+sub _wanted {
+  my $href = shift;
+  sub { /\.t$/ and -f $_ and $href->{$File::Find::dir} = 1 }
+}
+
+sub _add_author_tests {
+  my ($self, $dirs, $recurse) = @_;
+  return unless $Module::Install::AUTHOR;
+
+  my @tests = $self->tests ? (split / /, $self->tests) : 't/*.t';
+
+  # XXX: pick a default, later -- rjbs, 2008-02-24
+  my @dirs = @$dirs ? @$dirs : Carp::confess "no dirs given to author_tests";
+     @dirs = grep { -d } @dirs;
+
+  if ($recurse) {
+    require File::Find;
+    my %test_dir;
+    File::Find::find(_wanted(\%test_dir), @dirs);
+    $self->tests( join ' ', @tests, map { "$_/*.t" } sort keys %test_dir );
+  } else {
+    $self->tests( join ' ', @tests, map { "$_/*.t" } sort @dirs );
+  }
+}
+
+#line 107
+
+1;
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -4,7 +4,7 @@ package Module::Install::Base;
 use strict 'vars';
 use vars qw{$VERSION};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 }
 
 # Suspend handler for "redefined" warnings
@@ -9,7 +9,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -7,7 +7,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -34,6 +34,17 @@ sub prompt {
 	}
 }
 
+# Store a cleaned up version of the MakeMaker version,
+# since we need to behave differently in a variety of
+# ways based on the MM version.
+my $makemaker = eval $ExtUtils::MakeMaker::VERSION;
+
+# If we are passed a param, do a "newer than" comparison.
+# Otherwise, just return the MakeMaker version.
+sub makemaker {
+	( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0
+}
+
 sub makemaker_args {
 	my $self = shift;
 	my $args = ( $self->{makemaker_args} ||= {} );
@@ -44,7 +55,7 @@ sub makemaker_args {
 # For mm args that take multiple space-seperated args,
 # append an argument to the current list.
 sub makemaker_append {
-	my $self = sShift;
+	my $self = shift;
 	my $name = shift;
 	my $args = $self->makemaker_args;
 	$args->{name} = defined $args->{$name}
@@ -107,6 +118,9 @@ sub tests_recursive {
 	%test_dir = ();
 	require File::Find;
 	File::Find::find( \&_wanted_t, $dir );
+	if ( -d 'xt' and ($ENV{RELEASE_TESTING} or $self->author) ) {
+		File::Find::find( \&_wanted_t, 'xt' );
+	}
 	$self->tests( join ' ', map { "$_/*.t" } sort keys %test_dir );
 }
 
@@ -130,12 +144,13 @@ sub write {
 		# an underscore, even though its own version may contain one!
 		# Hence the funny regexp to get rid of it.  See RT #35800
 		# for details.
-		$self->build_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ );
-		$self->configure_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ );
+		my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/;
+		$self->build_requires(     'ExtUtils::MakeMaker' => $v );
+		$self->configure_requires( 'ExtUtils::MakeMaker' => $v );
 	} else {
 		# Allow legacy-compatibility with 5.005 by depending on the
 		# most recent EU:MM that supported 5.005.
-		$self->build_requires( 'ExtUtils::MakeMaker' => 6.42 );
+		$self->build_requires(     'ExtUtils::MakeMaker' => 6.42 );
 		$self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 );
 	}
 
@@ -145,49 +160,75 @@ sub write {
 	$args->{NAME}     = $self->module_name || $self->name;
 	$args->{VERSION}  = $self->version;
 	$args->{NAME}     =~ s/-/::/g;
+	$DB::single = 1;
 	if ( $self->tests ) {
 		$args->{test} = { TESTS => $self->tests };
+	} elsif ( -d 'xt' and ($self->author or $ENV{RELEASE_TESTING}) ) {
+		$args->{test} = {
+			TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ),
+		};
 	}
 	if ( $] >= 5.005 ) {
 		$args->{ABSTRACT} = $self->abstract;
 		$args->{AUTHOR}   = $self->author;
 	}
-	if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) {
-		$args->{NO_META} = 1;
+	if ( $self->makemaker(6.10) ) {
+		$args->{NO_META}   = 1;
+		#$args->{NO_MYMETA} = 1;
 	}
-	if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 and $self->sign ) {
+	if ( $self->makemaker(6.17) and $self->sign ) {
 		$args->{SIGN} = 1;
 	}
 	unless ( $self->is_admin ) {
 		delete $args->{SIGN};
 	}
 
-	# Merge both kinds of requires into prereq_pm
 	my $prereq = ($args->{PREREQ_PM} ||= {});
 	%$prereq = ( %$prereq,
-		map { @$_ }
+		map { @$_ } # flatten [module => version]
 		map { @$_ }
 		grep $_,
-		($self->configure_requires, $self->build_requires, $self->requires)
+		($self->requires)
 	);
 
 	# Remove any reference to perl, PREREQ_PM doesn't support it
 	delete $args->{PREREQ_PM}->{perl};
 
-	# merge both kinds of requires into prereq_pm
+	# Merge both kinds of requires into BUILD_REQUIRES
+	my $build_prereq = ($args->{BUILD_REQUIRES} ||= {});
+	%$build_prereq = ( %$build_prereq,
+		map { @$_ } # flatten [module => version]
+		map { @$_ }
+		grep $_,
+		($self->configure_requires, $self->build_requires)
+	);
+
+	# Remove any reference to perl, BUILD_REQUIRES doesn't support it
+	delete $args->{BUILD_REQUIRES}->{perl};
+
+	# Delete bundled dists from prereq_pm
 	my $subdirs = ($args->{DIR} ||= []);
 	if ($self->bundles) {
 		foreach my $bundle (@{ $self->bundles }) {
 			my ($file, $dir) = @$bundle;
 			push @$subdirs, $dir if -d $dir;
-			delete $prereq->{$file};
+			delete $build_prereq->{$file}; #Delete from build prereqs only
 		}
 	}
 
+	unless ( $self->makemaker('6.55_03') ) {
+		%$prereq = (%$prereq,%$build_prereq);
+		delete $args->{BUILD_REQUIRES};
+	}
+
 	if ( my $perl_version = $self->perl_version ) {
 		eval "use $perl_version; 1"
 			or die "ERROR: perl: Version $] is installed, "
 			. "but we need version >= $perl_version";
+
+		if ( $self->makemaker(6.48) ) {
+			$args->{MIN_PERL_VERSION} = $perl_version;
+		}
 	}
 
 	$args->{INSTALLDIRS} = $self->installdirs;
@@ -265,4 +306,4 @@ sub postamble {
 
 __END__
 
-#line 394
+#line 435
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -230,6 +230,8 @@ sub all_from {
 		die("The path '$file' does not exist, or is not a file");
 	}
 
+	$self->{values}{all_from} = $file;
+
 	# Some methods pull from POD instead of code.
 	# If there is a matching .pod, use that instead
 	my $pod = $file;
@@ -385,11 +387,10 @@ sub name_from {
 	}
 }
 
-sub perl_version_from {
-	my $self = shift;
+sub _extract_perl_version {
 	if (
-		Module::Install::_read($_[0]) =~ m/
-		^
+		$_[0] =~ m/
+		^\s*
 		(?:use|require) \s*
 		v?
 		([\d_\.]+)
@@ -398,6 +399,16 @@ sub perl_version_from {
 	) {
 		my $perl_version = $1;
 		$perl_version =~ s{_}{}g;
+		return $perl_version;
+	} else {
+		return;
+	}
+}
+
+sub perl_version_from {
+	my $self = shift;
+	my $perl_version=_extract_perl_version(Module::Install::_read($_[0]));
+	if ($perl_version) {
 		$self->perl_version($perl_version);
 	} else {
 		warn "Cannot determine perl version info from $_[0]\n";
@@ -425,13 +436,12 @@ sub author_from {
 	}
 }
 
-sub license_from {
-	my $self = shift;
+sub _extract_license {
 	if (
-		Module::Install::_read($_[0]) =~ m/
+		$_[0] =~ m/
 		(
 			=head \d \s+
-			(?:licen[cs]e|licensing|copyright|legal)\b
+			(?:licen[cs]e|licensing|copyrights?|legal)\b
 			.*?
 		)
 		(=head\\d.*|=cut.*|)
@@ -439,7 +449,9 @@ sub license_from {
 	/ixms ) {
 		my $license_text = $1;
 		my @phrases      = (
-			'under the same (?:terms|license) as (?:perl|the perl programming language) itself' => 'perl', 1,
+			'under the same (?:terms|license) as (?:perl|the perl programming language)' => 'perl', 1,
+			'under the terms of (?:perl|the perl programming language) itself' => 'perl', 1,
+			'Artistic and GPL'                   => 'perl',        1,
 			'GNU general public license'         => 'gpl',         1,
 			'GNU public license'                 => 'gpl',         1,
 			'GNU lesser general public license'  => 'lgpl',        1,
@@ -456,20 +468,32 @@ sub license_from {
 			'proprietary'                        => 'proprietary', 0,
 		);
 		while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) {
-			$pattern =~ s{\s+}{\\s+}g;
+			$pattern =~ s#\s+#\\s+#gs;
 			if ( $license_text =~ /\b$pattern\b/i ) {
-				$self->license($license);
-				return 1;
+			        return $license;
 			}
 		}
+	} else {
+	        return;
 	}
+}
 
-	warn "Cannot determine license info from $_[0]\n";
-	return 'unknown';
+sub license_from {
+	my $self = shift;
+	if (my $license=_extract_license(Module::Install::_read($_[0]))) {
+		$self->license($license);
+	} else {
+		warn "Cannot determine license info from $_[0]\n";
+		return 'unknown';
+	}
 }
 
 sub _extract_bugtracker {
-	my @links   = $_[0] =~ m#L<(\Qhttp://rt.cpan.org/\E[^>]+)>#g;
+	my @links   = $_[0] =~ m#L<(
+	 \Qhttp://rt.cpan.org/\E[^>]+|
+	 \Qhttp://github.com/\E[\w_]+/[\w_]+/issues|
+	 \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list
+	 )>#gx;
 	my %links;
 	@links{@links}=();
 	@links=keys %links;
@@ -485,7 +509,7 @@ sub bugtracker_from {
 		return 0;
 	}
 	if ( @links > 1 ) {
-		warn "Found more than on rt.cpan.org link in $_[0]\n";
+		warn "Found more than one bugtracker link in $_[0]\n";
 		return 0;
 	}
 
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';;
+	$VERSION = '0.93';;
 	@ISA     = qw{Module::Install::Base};
 	$ISCORE  = 1;
 }
@@ -28,7 +28,7 @@ BEGIN {
 	# This is not enforced yet, but will be some time in the next few
 	# releases once we can make sure it won't clash with custom
 	# Module::Install extensions.
-	$VERSION = '0.91';
+	$VERSION = '0.93';
 
 	# Storage for the pseudo-singleton
 	$MAIN    = undef;
@@ -348,17 +348,24 @@ sub _caller {
 	return $call;
 }
 
+# Done in evals to avoid confusing Perl::MinimumVersion
+eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _read {
 	local *FH;
-	if ( $] >= 5.006 ) {
-		open( FH, '<', $_[0] ) or die "open($_[0]): $!";
-	} else {
-		open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
-	}
+	open( FH, '<', $_[0] ) or die "open($_[0]): $!";
+	my $string = do { local $/; <FH> };
+	close FH or die "close($_[0]): $!";
+	return $string;
+}
+END_NEW
+sub _read {
+	local *FH;
+	open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
 	my $string = do { local $/; <FH> };
 	close FH or die "close($_[0]): $!";
 	return $string;
 }
+END_OLD
 
 sub _readperl {
 	my $string = Module::Install::_read($_[0]);
@@ -379,18 +386,26 @@ sub _readpod {
 	return $string;
 }
 
+# Done in evals to avoid confusing Perl::MinimumVersion
+eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _write {
 	local *FH;
-	if ( $] >= 5.006 ) {
-		open( FH, '>', $_[0] ) or die "open($_[0]): $!";
-	} else {
-		open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
+	open( FH, '>', $_[0] ) or die "open($_[0]): $!";
+	foreach ( 1 .. $#_ ) {
+		print FH $_[$_] or die "print($_[0]): $!";
 	}
+	close FH or die "close($_[0]): $!";
+}
+END_NEW
+sub _write {
+	local *FH;
+	open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
 	foreach ( 1 .. $#_ ) {
 		print FH $_[$_] or die "print($_[0]): $!";
 	}
 	close FH or die "close($_[0]): $!";
 }
+END_OLD
 
 # _version is for processing module versions (eg, 1.03_05) not
 # Perl versions (eg, 5.8.1).
@@ -427,4 +442,4 @@ sub _CLASS ($) {
 
 1;
 
-# Copyright 2008 - 2009 Adam Kennedy.
+# Copyright 2008 - 2010 Adam Kennedy.
@@ -1084,36 +1084,6 @@ set the appropriate content type and disposition.
 Controllers are the main point of communication between the web server
 and your application.  Here we explore some aspects of how they work.
 
-=head2 Extending RenderView (formerly DefaultEnd)
-
-The recommended approach for an C<end> action is to use
-L<Catalyst::Action::RenderView> (taking the place of
-L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
-However there are times when you need to add a bit to it, but don't want
-to write your own C<end> action.
-
-You can extend it like this:
-
-To add something to an C<end> action that is called before rendering
-(this is likely to be what you want), simply place it in the C<end>
-method:
-
-    sub end : ActionClass('RenderView') {
-      my ( $self, $c ) = @_;
-      # do stuff here; the RenderView action is called afterwards
-    }
-
-To add things to an C<end> action that are called I<after> rendering,
-you can set it up like this:
-
-    sub render : ActionClass('RenderView') { }
-
-    sub end : Private {
-      my ( $self, $c ) = @_;
-      $c->forward('render');
-      # do stuff here
-    }
-
 =head2 Action Types
 
 =head3 Introduction
@@ -1329,11 +1299,12 @@ will both be called when visiting
 You can put root actions in your main MyApp.pm file, but this is deprecated,
 please put your actions into your Root controller.
 
-=head3 More Information
+=head3 Flowchart
 
-L<http://dev.catalyst.perl.org/wiki/FlowChart>
+A graphical flowchart of how the dispatcher works can be found on the wiki at
+L<http://dev.catalyst.perl.org/attachment/wiki/WikiStart/catalyst-flow.png>.
 
-=head2 DRY Controllers with Chained actions.
+=head2 DRY Controllers with Chained actions
 
 Imagine that you would like the following paths in your application:
 
@@ -1510,6 +1481,38 @@ information on passing arguments via C<forward>.)
   use base qw/Catalyst::Controller/;
 
   sub key1 : Chained('/')
+  
+=head2 Extending RenderView (formerly DefaultEnd)
+
+The recommended approach for an C<end> action is to use
+L<Catalyst::Action::RenderView> (taking the place of
+L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
+However there are times when you need to add a bit to it, but don't want
+to write your own C<end> action.
+
+You can extend it like this:
+
+To add something to an C<end> action that is called before rendering
+(this is likely to be what you want), simply place it in the C<end>
+method:
+
+    sub end : ActionClass('RenderView') {
+      my ( $self, $c ) = @_;
+      # do stuff here; the RenderView action is called afterwards
+    }
+
+To add things to an C<end> action that are called I<after> rendering,
+you can set it up like this:
+
+    sub render : ActionClass('RenderView') { }
+
+    sub end : Private {
+      my ( $self, $c ) = @_;
+      $c->forward('render');
+      # do stuff here
+    }
+
+  
 
 =head1 Deployment
 
@@ -357,7 +357,7 @@ Now we can create a DBIC::Schema model for this database.
 
     script/myapp_create.pl model MyModel DBIC::Schema MySchema create=static 'dbi:SQLite:/tmp/myapp.db'
 
-L<DBIx::Class::Schema::Loader> can automaticall load table layouts and
+L<DBIx::Class::Schema::Loader> can automatically load table layouts and
 relationships, and convert them into a static schema definition
 C<MySchema>, which you can edit later.
 
@@ -72,8 +72,8 @@ catalyst subversion repository by issuing the command:
 
     svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/ CatalystTutorial
 
-This will download the most recent tarball for each chapter of the 
-tutorial into the CatalystTutorial directory on your machine. 
+This will download the most recent code for each chapter of the
+tutorial into the CatalystTutorial directory on your machine.
 
 B<These reference implementations are provided so that when you follow
 the tutorial, you can use the code from the subversion repository to
@@ -185,11 +185,96 @@ Subversion repository at
 L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/>.
 
 
+=head1 QUICK START
+
+For those who want to get going quickly, here is a short "cookbook-style 
+recipe" to quickly get you up and running. Although there are many 
+different ways to get a Catalyst environment going, this tutorial has 
+been written with and tested against Debian 5 Live CD, using the steps 
+in this Quick Start. 
+
+If you want, you can follow the directions in this section and then jump 
+right to L<Chapter 2|Catalyst::Manual::Tutorial::02_CatalystBasics> of 
+the tutorial. However, it would be a good idea to come back and read the 
+sections below the Quick Start when you have time. Or, continue reading 
+those other sections for suggestions if you do not wish to use the 
+Debian 5 Live CD. 
+
+
+=over 4
+
+=item 1 
+
+Download the C<debian-live-503-i386-rescue.iso> image from
+L<http://cdimage.debian.org/cdimage/release/current-live/i386/iso-cd/>.
+
+=item 2
+
+Boot this disk, either in a physical machine, or possibly some sort
+of virtual machine (can be a very handy way to practice).
+
+=item 3
+
+Select "C<Live>" from the initial boot menu.
+
+=item 4
+
+At the "C<user@debian:~$>" prompt, type:
+
+    sudo aptitude -y install subversion
+
+=item 5
+
+If you want to be able to remotely SSH to this system, set a
+password for root:
+
+    sudo passwd
+    ...
+
+=item 6
+
+Add the "unstable" Debian package repository:
+
+    sudo vi /etc/apt/sources.list
+
+Add the following line to the bottom of this file:
+
+    deb http://ftp.us.debian.org/debian/ unstable main
+
+=item 7
+
+Install Catalyst and related libraries:
+
+    sudo aptitude update
+    sudo aptitude -y install sqlite3 libdbd-sqlite3-perl libcatalyst-perl \
+        libcatalyst-modules-perl libdbix-class-timestamp-perl \
+        libdatetime-format-sqlite-perl libconfig-general-perl \
+        libhtml-formfu-model-dbic-perl libterm-readline-perl-perl \
+        libdbix-class-encodedcolumn-perl libperl6-junction-perl \
+        libtest-pod-perl
+    sudo aptitude clean
+
+=item 8
+
+Test example code:
+
+    mkdir test
+    cd test
+    svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter8
+    cd MyApp_Chapter8/MyApp
+    CATALYST_DEBUG=0 prove -wl t
+    cd
+
+=back
+
+
 =head1 VERSIONS AND CONVENTIONS USED IN THIS TUTORIAL
 
 This tutorial was built using the following resources. Please note that
 you may need to make adjustments for different environments and
-versions:
+versions (note that trailing zeros in version numbers are not 
+significant and may get dropped with techniques for viewing them;
+for example, Catalyst v5.80020 might show up as 5.8002):
 
 =over 4
 
@@ -199,20 +284,25 @@ Debian 5 (Lenny)
 
 =item * 
 
-Catalyst v5.80013
+Catalyst v5.80020 (note: may show up as '5.8002' without the trailing zero)
 
 =item *
 
-Catalyst::Devel v1.21
+Catalyst::Devel v1.26
 
 =item * 
 
-DBIx::Class v0.08112
+DBIx::Class v0.08115
+
+=item *
+
+Catalyst::Model::DBIC::Schema v0.40
 
 =item *
 
 Template Toolkit v2.20
 
+
 =item * 
 
 Catalyst Plugins
@@ -226,11 +316,11 @@ use. This tutorial has been tested against the following set of plugins:
 
 =item * 
 
-Catalyst::Plugin::Authentication -- v0.10015
+Catalyst::Plugin::Authentication -- v0.10016
 
 =item *
 
-Catalyst::Plugin::Authorization::Roles -- v0.07
+Catalyst::Plugin::Authorization::Roles -- v0.08
 
 =item *
 
@@ -254,10 +344,14 @@ Catalyst::Plugin::StackTrace -- v0.11
 
 =item *
 
-Catalyst::Plugin::Static::Simple -- v0.25
+Catalyst::Plugin::Static::Simple -- v0.29
 
 =back
 
+=item *
+
+HTML::FormFu -- v0.06001
+
 =item * 
 
 B<NOTE:> You can check the versions you have installed with the
@@ -325,7 +419,8 @@ hard to guarantee this.>
 =item * 
 
 Download one of the ISO files from 
-L<http://cdimage.debian.org/cdimage/release/current-live/i386/iso-cd/>. 
+L<http://cdimage.debian.org/cdimage/release/current-live/i386/iso-cd/>
+(the current version at the time this was written was 5.0.3). 
 You can pick any one of the live CD variations will work, but 
 you may wish to consider the following points:
 
@@ -333,7 +428,7 @@ you may wish to consider the following points:
 
 =item *
 
-"C<debian-live-500-i386-rescue.iso>" is probably the best all-around 
+"C<debian-live-503-i386-rescue.iso>" is probably the best all-around 
 option for most people because it includes many extra tools such as 
 the GCC compiler, therefore saving RAM (every package you need to 
 install when running from live CD consumes memory because RAM disk is 
@@ -344,7 +439,7 @@ should be able to safely ignore these.
 
 =item *
 
-"C<debian-live-500-i386-standard.iso>" is a great option because of 
+"C<debian-live-503-i386-standard.iso>" is a great option because of 
 its compact size, but you will probably need approximately 1 GB of RAM 
 in the computer where you will run the tutorial.  Because the 
 "standard" live CD comes with with a minimal set of tools, we will 
@@ -377,9 +472,21 @@ Select "C<Live>" from the initial boot menu.
 
 =item *
 
-Once the system has booted to a "C<user@debian:~$>" prompt, enter the 
-following command to add the more current "unstable" package 
-repository:
+Once the system has booted to a "C<user@debian:~$>" prompt, first
+install the Subversion client in case you want to check out the
+completed chapter example code:
+
+    sudo aptitude -y install subversion
+
+If you want to be able to remotely SSH to this system, set a
+password for root:
+
+    sudo passwd
+    ...
+
+Then enter the following command to add the more current "unstable" 
+package repository so we get the latest versions of Catalyst and
+related packages:
 
     sudo vi /etc/apt/sources.list
 
@@ -401,9 +508,10 @@ Install Catalyst:
     sudo aptitude update
     sudo aptitude -y install sqlite3 libdbd-sqlite3-perl libcatalyst-perl \
         libcatalyst-modules-perl libdbix-class-timestamp-perl \
-        libdbix-class-encodedcolumn-perl libperl6-junction-perl \
         libdatetime-format-sqlite-perl libconfig-general-perl \
-        libhtml-formfu-model-dbic-perl
+        libhtml-formfu-model-dbic-perl libterm-readline-perl-perl \
+        libdbix-class-encodedcolumn-perl libperl6-junction-perl \
+        libtest-pod-perl
 
 Let it install (normally about a 30 to 90-second operaton) and you are 
 done. (Note the '\' above.  Depending on your environment, you might 
@@ -617,19 +725,17 @@ of each part for the appropriate svn command to use).
 B<NOTE:> You can run the test cases for the final code through Chapter 8 
 with the following commands:
 
-    wget http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter8.tgz
-    tar zxvf MyApp_Chapter8.tgz
-    cd MyApp
-    CATALYST_DEBUG=0 prove --lib lib t
+    svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter8
+    cd MyApp_Chapter8/MyApp
+    CATALYST_DEBUG=0 prove -wl t
 
-If you wish to include the L<HTML::FormFu|HTML::FormFu> section in 
-your tests, substitute C<MyApp_Chapter9_FormFu.tgz> for 
-C<MyApp_Chapter8.tgz> in the URL above.
+If you wish to include the L<HTML::FormFu|HTML::FormFu> section in your tests,
+substitute C<MyApp_Chapter9_FormFu> for C<MyApp_Chapter8> in the URL
+above (don't forget to "cd" out of the Ch8 directory if you ran the code above).
 
-    wget http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter9_FormFu.tgz
-    tar zxvf MyApp_Chapter8.tgz
-    cd MyApp
-    CATALYST_DEBUG=0 prove --lib lib t
+    svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter9_FormFu
+    cd MyApp_Chapter9_FormFu/MyApp
+    CATALYST_DEBUG=0 prove -wl t
 
 You can also fire up the application under the development server that is conveniently
 built in to Catalyst.  Just issue this command from the C<MyApp> directory where you
@@ -188,13 +188,20 @@ Run the following command to start up the built-in development web
 server (make sure you didn't forget the "C<cd Hello>" from the 
 previous step):
 
-    $ script/hello_server.pl
+B<Note>: The "-r" argument enables reloading on code changes so you 
+don't have to stop and start the server when you update code. See 
+C<perldoc script/hello_server.pl> for additional options you might find 
+helpful. Most of the rest of the tutorial will assume that you are using 
+"-r" when you start the development server, but feel free to manually 
+start and stop it (use C<Ctrl-C> to break out of the dev server) if you 
+prefer. 
+
+    $ script/hello_server.pl -r
     [debug] Debug messages enabled
     [debug] Statistics enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
     | Catalyst::Plugin::ConfigLoader  0.27                                       |
-    | Catalyst::Plugin::Static::Simple  0.25                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -221,11 +228,11 @@ previous step):
     .-------------------------------------+--------------------------------------.
     | Path                                | Private                              |
     +-------------------------------------+--------------------------------------+
-    | /                                   | /default                             |
     | /                                   | /index                               |
+    | /                                   | /default                             |
     '-------------------------------------+--------------------------------------'
     
-    [info] Hello powered by Catalyst 5.80013
+    [info] Hello powered by Catalyst 5.80020
     You can connect to your server at http://debian:3000
 
 Point your web browser to L<http://localhost:3000> (substituting a 
@@ -235,17 +242,19 @@ screen or an "Index" screen, you probably forgot to specify port 3000
 in your URL).  Information similar to the following should be appended 
 to the logging output of the development server:
 
-    [info] *** Request 1 (0.005/s) [20712] [Sun Oct 11 11:58:51 2009] ***
-    [debug] "GET" request for "/" from "172.0.0.1"
-    [info] Request took 0.007342s (136.203/s)
-    .----------------------------------------------------------------+-----------.
-    | Action                                                         | Time      |
-    +----------------------------------------------------------------+-----------+
-    | /index                                                         | 0.000491s |
-    | /end                                                           | 0.000595s |
-    '----------------------------------------------------------------+-----------'
+    [info] *** Request 1 (0.001/s) [23194] [Sat Jan 16 11:09:18 2010] ***
+    [debug] "GET" request for "/" from "127.0.0.1"
+    [debug] Path is "/"
+    [info] Request took 0.004851s (206.143/s)
+    .------------------------------------------------------------+-----------.
+    | Action                                                     | Time      |
+    +------------------------------------------------------------+-----------+
+    | /index                                                     | 0.000395s |
+    | /end                                                       | 0.000425s |
+    '------------------------------------------------------------+-----------'
 
-Press Ctrl-C to break out of the development server.
+B<Note>: Press C<Ctrl-C> to break out of the development server if 
+necessary.
 
 
 =head1 HELLO WORLD
@@ -256,9 +265,7 @@ The Root.pm controller is a place to put global actions that usually
 execute on the root URL. Open the C<lib/Hello/Controller/Root.pm> file in 
 your editor. You will see the "index" subroutine, which is 
 responsible for displaying the welcome screen that you just saw in 
-your browser. Later on you'll want to change that to something more 
-reasonable, such as a "404" message or a redirect, but for now just 
-leave it alone.
+your browser. 
 
     sub index :Path :Args(0) {
         my ( $self, $c ) = @_;
@@ -267,6 +274,9 @@ leave it alone.
         $c->response->body( $c->welcome_message );
     }
 
+Later on you'll want to change that to something more reasonable, such 
+as a "404" message or a redirect, but for now just leave it alone. 
+
 The "C<$c>" here refers to the Catalyst context, which is used to 
 access the Catalyst application. In addition to many other things, 
 the Catalyst context provides access to "response" and "request" 
@@ -275,14 +285,14 @@ L<Catalyst::Response|Catalyst::Response>, and
 L<Catalyst::Request|Catalyst::Request>) 
 
 C<$c-E<gt>response-E<gt>body> sets the HTTP response (see 
-L<Catalyst::Response|Catalyst::Response>), while C<$c-E<gt>welcome_message> 
-is a special method that returns the welcome message that you saw in 
-your browser.
+L<Catalyst::Response|Catalyst::Response>), while 
+C<$c-E<gt>welcome_message> is a special method that returns the 
+welcome message that you saw in your browser.
 
 The ":Path :Args(0)" after the method name are attributes which 
 determine which URLs will be dispatched to this method. (You might see 
 ":Private" if you are using an older version of Catalyst, but using 
-that with 'default' or 'index' is currently deprecated.  If so, you 
+that with "default" or "index" is currently deprecated.  If so, you 
 should also probably upgrade before continuing the tutorial.)
 
 Some MVC frameworks handle dispatching in a central place. Catalyst, 
@@ -303,7 +313,7 @@ C<create> method.
 Add the following subroutine to your C<lib/Hello/Controller/Root.pm> 
 file:
 
-    sub hello : Global {
+    sub hello :Global {
         my ( $self, $c ) = @_;
         
         $c->response->body("Hello, World!");
@@ -314,10 +324,36 @@ cutting and pasting example code from POD-based documents.
 
 Here you're sending your own string to the webpage.
 
-Save the file, start the server (stop and restart it if it's still 
-running), and go to L<http://localhost:3000/hello> to 
-see "Hello, World!"  Also notice that a new action is listed under
-"Loaded Private actions" in the development server debug output.
+Save the file, and you should notice the following in your server output:
+
+    Saw changes to the following files:
+     - /home/me/Hello/lib/Hello/Controller/Root.pm (modify)
+    
+    Attempting to restart the server
+    ...
+    [debug] Loaded Private actions:
+    .----------------------+--------------------------------------+--------------.
+    | Private              | Class                                | Method       |
+    +----------------------+--------------------------------------+--------------+
+    | /default             | Hello::Controller::Root              | default      |
+    | /end                 | Hello::Controller::Root              | end          |
+    | /index               | Hello::Controller::Root              | index        |
+    | /hello               | Hello::Controller::Root              | hello        |
+    '----------------------+--------------------------------------+--------------'
+    
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /                                   | /index                               |
+    | /                                   | /default                             |
+    | /hello                              | /hello                               |
+    '-------------------------------------+--------------------------------------'
+    ...
+
+Go to L<http://localhost:3000/hello> to see "Hello, World!".   Also 
+notice that the newly defined 'hello' action is listed under "Loaded 
+Private actions" in the development server debug output.
 
 
 =head2 Hello, World! Using a View and a Template
@@ -360,7 +396,7 @@ contains a config statement to set the TT extension to ".tt".
 
 Now that the TT.pm "View" exists, Catalyst will autodiscover it and be 
 able to use it to display the view templates using the "process" 
-method that it inherits from the C<Catalyst::View::TT class>.
+method that it inherits from the C<Catalyst::View::TT> class.
 
 Template Toolkit is a very full featured template facility, with 
 excellent documentation at L<http://template-toolkit.org/>, 
@@ -371,7 +407,7 @@ chapters of the tutorial).
 Create a C<root/hello.tt> template file (put it in the C<root> under 
 the C<Hello> directory that is the base of your application). Here is 
 a simple sample:
-  
+
     <p>
         This is a TT view template, called '[% template.name %]'.
     </p>
@@ -384,10 +420,10 @@ template file (C<hello.tt>).  The rest of the template is normal HTML.
 Change the hello method in C<lib/Hello/Controller/Root.pm> to the 
 following:
 
-    sub hello : Global {
+    sub hello :Global {
         my ( $self, $c ) = @_;
         
-        $c->stash->{template} = 'hello.tt';
+        $c->stash(template => 'hello.tt');
     }
 
 This time, instead of doing C<$c-E<gt>response-E<gt>body()>, you are 
@@ -400,9 +436,37 @@ default) view to be rendered (unless there's a C<$c-E<gt>response-
 E<gt>body()> statement). So your template will be magically displayed 
 at the end of your method.
 
-After saving the file, restart the development server, and look at 
-L<http://localhost:3000/hello> again. You should 
-see the template that you just made.
+After saving the file, the development server should automatically
+restart (again, the tutorial is written to assume that you are
+using the "-r" option -- manually restart it if you aren't), 
+and look at L<http://localhost:3000/hello> in your again. You 
+should see the template that you just made.
+
+B<TIP:> If you keep the server running with "-r" in a "background 
+window," don't let that window get totally hidden... if you have an 
+syntax error in your code, the debug server output will contain the 
+error information.
+
+B<Note:> You will probably run into a variation of the "stash"
+statement above that looks like:
+
+    $c->stash->{template} = 'hello.tt';
+
+Although this style is still relatively common, the approach we
+used previous is becoming more common because it allows you to
+set multiple stash variables in one line.  For example:
+
+    $c->stash(template => 'hello.tt', foo => 'bar', 
+              another_thing => 1);
+
+You can also set multiple stash values with a hashref:
+
+    $c->stash({template => 'hello.tt', foo => 'bar', 
+              another_thing => 1});
+
+Any of these formats work, but the C<$c-E<gt>stash(name =E<gt> value);>
+style is growing in popularity -- you may wish to use it all the 
+time (even when you are only setting a single value).
 
 
 =head1 CREATE A SIMPLE CONTROLLER AND AN ACTION
@@ -417,11 +481,11 @@ not much there.
 
 In C<lib/Hello/Controller/Site.pm>, add the following method:
 
-    sub test : Local {
+    sub test :Local {
         my ( $self, $c ) = @_;
     
-        $c->stash->{username} = "John";
-        $c->stash->{template} = 'site/test.tt';
+        $c->stash(username => 'John',
+                  template => 'site/test.tt');
     }
 
 Notice the "Local" attribute on the C<test> method. This will cause 
@@ -448,13 +512,13 @@ template file at that location. Include a line like:
 
     <p>Hello, [% username %]!</p>
 
-Bring up or restart the server.  Notice in the server output that 
-C</site/test> is listed in the Loaded Path actions. Go to 
-L<http://localhost:3000/site/test> in your browser.
-
 You should see your test.tt file displayed, including the name "John"
 that you set in the controller.
 
+Once the server automatically restarts, notice in the server 
+output that C</site/test> is listed in the Loaded Path actions. 
+Go to L<http://localhost:3000/site/test> in your browser.
+
 
 =head1 AUTHORS
 
@@ -102,12 +102,14 @@ the command if you are using Strawberry Perl.)
 
 =head1 EDIT THE LIST OF CATALYST PLUGINS
 
-One of the greatest benefits of Catalyst is that it has such a large
-library of plugins and base classes available.  Plugins are used to
-seamlessly integrate existing Perl modules into the overall Catalyst
-framework.  In general, they do this by adding additional methods to the
-C<context> object (generally written as C<$c>) that Catalyst passes to
-every component throughout the framework.
+One of the greatest benefits of Catalyst is that it has such a large 
+library of bases classes and plugins available that you can use easily 
+add functionality to your application. Plugins are used to seamlessly 
+integrate existing Perl modules into the overall Catalyst framework. In 
+general, they do this by adding additional methods to the C<context> 
+object (generally written as C<$c>) that Catalyst passes to every 
+component throughout the framework. 
+
 
 By default, Catalyst enables three plugins/flags:
 
@@ -200,20 +202,22 @@ For our application, we want to add one new plugin into the mix.  To
 do this, edit C<lib/MyApp.pm> (this file is generally referred to as 
 your I<application class>) and delete the lines with:
 
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple/;
+    use Catalyst qw/
+        -Debug
+        ConfigLoader
+        Static::Simple
+    /;
 
 Then replace it with:
 
     # Load plugins
     use Catalyst qw/
-                    -Debug
-                    ConfigLoader
-                    Static::Simple
-                
-                    StackTrace
-                    /;
+        -Debug
+        ConfigLoader
+        Static::Simple
+    
+        StackTrace
+    /;
 
 B<Note:> Recent versions of C<Catalyst::Devel> have used a variety of 
 techniques to load these plugins/flags.  For example, you might see
@@ -224,7 +228,7 @@ the following:
 Don't let these variations confuse you -- they all accomplish the same 
 result.
 
-This tells Catalyst to start using one new plugin, 
+This tells Catalyst to start using one additional plugin, 
 L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>, to add a 
 stack trace to the standard Catalyst "debug screen" (the screen 
 Catalyst sends to your browser when an error occurs). Be aware that 
@@ -233,7 +237,7 @@ browser, not in the console window from which you're running your
 application, which is where logging output usually goes.
 
 Make sure when adding new plugins you also include them as a new
-dependancy within the Makefile.PL file. For example, after adding
+dependency within the Makefile.PL file. For example, after adding
 the StackTrace plugin the Makefile.PL should include the following
 line:
 
@@ -291,7 +295,7 @@ and add the following method to the controller:
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
@@ -299,14 +303,14 @@ and add the following method to the controller:
     
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
-        # $c->stash->{books} = [$c->model('DB::Book')->all];
+        # $c->stash(books => [$c->model('DB::Book')->all]);
         # But, for now, use this code until we create the model later
-        $c->stash->{books} = '';
+        $c->stash(books => '');
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 B<TIP>: See Appendix 1 for tips on removing the leading spaces when
@@ -321,7 +325,7 @@ is used to pass information between components and provide access to
 Catalyst and plugin functionality.
 
 Catalyst actions are regular Perl methods, but they make use of 
-attributes (the "C<: Local>" next to the "C<sub list>" in the code 
+attributes (the "C<:Local>" next to the "C<sub list>" in the code 
 above) to provide additional information to the Catalyst dispatcher 
 logic (note that the space between the colon and the attribute name is 
 optional; you will see attributes written both ways).  Most Catalyst 
@@ -541,7 +545,7 @@ rightfully belongs in a model class.
 
 To test your work so far, first start the development server:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 Then point your browser to L<http://localhost:3000> and you should
 still get the Catalyst welcome page.  Next, change the URL in your
@@ -563,14 +567,12 @@ In this step, we make a text file with the required SQL commands to
 create a database table and load some sample data.  We will use 
 SQLite (L<http://www.sqlite.org>), a popular database that is
 lightweight and easy to use. Be sure to get at least version 3. Open
-create a database table and load some sample data.  We will use
-L<SQLite|http://www.sqlite.org>, a popular database that is
-lightweight and easy to use. Be sure to get at least version 3. Open
 C<myapp01.sql> in your editor and enter:
 
     --
     -- Create a very simple database to hold book and author information
     --
+    PRAGMA foreign_keys = ON;
     CREATE TABLE book (
             id          INTEGER PRIMARY KEY,
             title       TEXT ,
@@ -578,8 +580,8 @@ C<myapp01.sql> in your editor and enter:
     );
     -- 'book_author' is a many-to-many join table between books & authors
     CREATE TABLE book_author (
-            book_id     INTEGER,
-            author_id   INTEGER,
+            book_id     INTEGER REFERENCES book(id) ON DELETE CASCADE ON UPDATE CASCADE,
+            author_id   INTEGER REFERENCES author(id) ON DELETE CASCADE ON UPDATE CASCADE,
             PRIMARY KEY (book_id, author_id)
     );
     CREATE TABLE author (
@@ -625,8 +627,9 @@ can use the SQLite command line environment to do a quick dump of the
 database contents:
 
     $ sqlite3 myapp.db
-    SQLite version 3.5.9
+    SQLite version 3.6.22
     Enter ".help" for instructions
+    Enter SQL statements terminated with a ";"
     sqlite> select * from book;
     1|CCSP SNRS Exam Certification Guide|5
     2|TCP/IP Illustrated, Volume 1|5
@@ -651,14 +654,14 @@ required if you do a single SQL statement on the command line).  Use
 ".q" to exit from SQLite from the SQLite interactive mode and return to
 your OS command prompt.
 
-Please note that here we have chosen to use 'singular' table names. This
-is because the default inflection code for L<DBIx::Class::Schema::Loader>
-does NOT handle plurals. There has been much philosophical discussion
-on whether table names should be plural or singular. There is no one
-correct answer, as long as one makes a choice and remains consistent
-with it. If you prefer plural table names (e.g. they are easier and
-more natural to read) then you will need to pass it an inflect_map 
-option. See L<DBIx::Class::Schema::Loader> for more information.
+Please note that here we have chosen to use 'singular' table names. This is
+because the default inflection code for older versions of
+L<DBIx::Class::Schema::Loader> does NOT handle plurals. There has been much
+philosophical discussion on whether table names should be plural or singular.
+There is no one correct answer, as long as one makes a choice and remains
+consistent with it. If you prefer plural table names (e.g. you think that they
+are easier to read) then see the documentation in
+L<DBIx::Class::Schema::Loader::Base/naming> (version 0.05 or greater).
 
 For using other databases, such as PostgreSQL or MySQL, see 
 L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices>.
@@ -689,25 +692,36 @@ framework, a technique that we see in Chapter 4).
 =head2 Make Sure You Have a Recent Version of the DBIx::Class Model
 
 First, let's be sure we have a recent version of the DBIC helper,
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, by
-running this command:
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, so
+that we can take advantage of some recent enhancements in how
+foreign keys are handled with SQLite.  To check your version, 
+run this command:
 
     $ perl -MCatalyst::Model::DBIC::Schema -e \
         'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.31
+    0.4
 
 Please note the '\' above.  Depending on your environment, you might 
 be able to cut and paste the text as shown or need to remove the '\' 
 character to that the command is all on a single line.
 
-You should have version 0.31 or greater if you are following along 
-with Debian 5.  In other environments, you may need to run this 
-command to install it directly from CPAN:
+If you are following along in Debian 5, you should have version 0.40 or 
+higher (shown above as "0.4" with the tailing zero removed). If you have 
+less than v0.39, you will need to run this command to install it 
+directly from CPAN: 
 
     $ sudo cpan Catalyst::Model::DBIC::Schema
 
 And re-run the version print command to verify that you are now at 
-0.31 or higher.
+0.39 or higher.
+
+In addition, since we are using SQLite's foreign key support here,
+please be sure that you use version C<1.27> of L<DBD::SQLite> or later:
+
+    $ perl -MDBD::SQLite -e 'print "$DBD::SQLite::VERSION\n"'
+    1.29
+
+Upgrade if you are not at version C<1.27> or higher.
 
 
 =head2 Create Static DBIx::Class Schema Files
@@ -719,7 +733,8 @@ L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> and
 automatically build the required files for us:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static dbi:SQLite:myapp.db
+        create=static dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
      exists "/home/me/MyApp/script/../lib/MyApp/Model"
      exists "/home/me/MyApp/script/../t"
     Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
@@ -758,9 +773,21 @@ into files.
 
 =item *
 
-And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
+C<dbi:SQLite:myapp.db> is the standard DBI connect string 
 for use with SQLite.
 
+=item *
+
+And finally, the C<on_connect_do> string requests that 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> create 
+foreign key relationships for us (this is not needed for databases such 
+as PostgreSQL and MySQL, but is required for SQLite). If you take a look 
+at C<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is 
+propogated to the Model, so that SQLite's recent (and optional) foreign 
+key enforcement is enabled at the start of every database connection. 
+
+
+
 =back
 
 If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
@@ -800,31 +827,15 @@ C<load_namspaces>.  For new applications, please try to use
 C<load_namespaces> since it more easily supports a very useful DBIC 
 technique called "ResultSet Classes."  If you need to convert an 
 existing application from "load_classes" to "load_namespaces," you can 
-use this process to automate the migration (but first make sure you 
-have v0.23 C<Catalyst::Model::DBIC::Schema> as discussed above):
+use this process to automate the migration, but first make sure you have
+version C<0.39> of L<Catalyst::Model::DBIC::Schema> and
+L<DBIx::Class::Schema::Loader> version C<0.05000> or later.
 
-    $ # First delete the existing schema file to disable "compatibility" mode
-    $ rm lib/MyApp/Schema.pm
-    $
-    $ # Then re-run the helper to build the files for "load_namespaces"
+    $ # Re-run the helper to upgrade for you
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static dbi:SQLite:myapp.db
-    $
-    $ # Now convert the existing files over
-    $ cd lib/MyApp/Schema
-    $ perl -MIO::All -e 'for (@ARGV) { my $s < io($_); $s =~ s/.*\n\# You can replace.*?\n//s;
-          $s =~ s/'MyApp::Schema::/'MyApp::Schema::Result::/g; my $d < io("Result/$_");
-          $d =~ s/1;\n?//; "$d$s" > io("Result/$_"); }' *.pm
-    $ cd ../../..
-    $
-    $ # And finally delete the old files
-    $ rm lib/MyApp/Schema/*.pm
-
-The "C<perl -MIO::ALL ...>" script will copy all the customized 
-relationship (and other) information below "C<# DO NOT MODIFY>" line 
-from the old files in C<lib/MyApp/Schema> to the new files in 
-C<lib/MyApp/Schema/Result> (we will be starting to add some 
-"customized relationship information in the section below).
+        create=static naming=current use_namespaces=1 \
+        dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
 
 
 =head1 ENABLE THE MODEL IN THE CONTROLLER
@@ -840,20 +851,20 @@ and delete the next 2 lines):
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
     
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
+        # Retrieve all of the book records as book model objects and store
+        # in the stash where they can be accessed by the TT template
+        $c->stash(books => [$c->model('DB::Book')->all]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
 B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented 
@@ -883,9 +894,11 @@ and L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>.
 First, let's enable an environment variable that causes DBIx::Class to 
 dump the SQL statements used to access the database.  This is a 
 helpful trick when you are trying to debug your database-oriented 
-code:
+code.  Press C<Ctrl-C> to break out of the development server and
+enter:
 
     $ export DBIC_TRACE=1
+    $ script/myapp_server.pl -r 
 
 This assumes you are using bash as your shell -- adjust accordingly if
 you are using a different shell (for example, under tcsh, use
@@ -900,14 +913,13 @@ log).
 Then launch the Catalyst development server.  The log output should
 display something like:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
     [debug] Debug messages enabled
     [debug] Statistics enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
     | Catalyst::Plugin::ConfigLoader  0.27                                       |
     | Catalyst::Plugin::StackTrace  0.11                                         |
-    | Catalyst::Plugin::Static::Simple  0.25                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -948,7 +960,7 @@ display something like:
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
     
-    [info] MyApp powered by Catalyst 5.80013
+    [info] MyApp powered by Catalyst 5.80020
     You can connect to your server at http://debian:3000
 
 B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
@@ -1161,35 +1173,127 @@ provide lots of high-quality CSS functionality.
 
 =head2 Test Run The Application
 
-Restart the development server and hit "Reload" in your web browser
-and you should now see a formatted version of our basic book list.
-Although our wrapper and stylesheet are obviously very simple, you
-should see how it allows us to control the overall look of an entire
-website from two central files.  To add new pages to the site, just
-provide a template that fills in the C<content> section of our wrapper
-template -- the wrapper will provide the overall feel of the page.
+Hit "Reload" in your web browser and you should now see a formatted 
+version of our basic book list. (Again, the development server should 
+have automatically restarted when you made changes to 
+C<lib/MyApp/View/TT.pm>. If you are not using the "-r" option, you will 
+need to hit C<Ctrl-C> and manually restart it. Also note that the 
+development server does I<NOT> need to restart for changes to the TT and 
+static files we created and edited in the C<root> directory -- those 
+updates are handled on a per-request basis.) 
+
+Although our wrapper and stylesheet are obviously very simple, you 
+should see how it allows us to control the overall look of an entire 
+website from two central files. To add new pages to the site, just 
+provide a template that fills in the C<content> section of our wrapper 
+template -- the wrapper will provide the overall feel of the page. 
 
 
 =head2 Updating the Generated DBIx::Class Result Class Files
 
-Let's manually add some relationship information to the auto-generated 
-Result Class files. (Note: if you are using a database other than 
-SQLite, such as PostgreSQL, then the relationship could have been 
-automatically placed in the Result Class files.  If so, you can skip 
-this step.)  First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
-following text below the C<# You can replace this text...> comment:
+If you take a look at the Schema files automatically generated by 
+L<DBIx::Class::Schema::Loader>, you will see that it has already defined 
+C<has_many> and C<belongs_to> relationships on each side of our foreign 
+keys. For example, take a look at C<lib/MyApp/Schema/Result/Book.pm> and 
+notice the following code: 
+
+    =head1 RELATIONS
+
+    =head2 book_authors
+
+    Type: has_many
+
+    Related object: L<MyApp::Schema::Result::BookAuthor>
+
+    =cut
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      { "foreign.book_id" => "self.id" },
+    );
+
+Each C<Book> "has_many" C<book_authors>, where C<BookAuthor> is
+the many-to-many table that allows each Book to have multiple
+Authors, and each Author to have mulitple books.  The arguments
+to C<has_many> are:
+
+=over 4
+
+=item *
+
+C<book_authors> - The name for this relationship.  DBIC will create
+an accessor on the C<Books> DBIC Row object with this name.
+
+=item *
+
+C<MyApp::Schema::Result::BookAuthor> - The name of the DBIC model
+class referenced by this C<has_many> relationship.
+
+=item *
+
+C<foreign.book_id> - C<book_id> is the name of the foreign key 
+column in the I<foreign> table that points back to this table.
+
+=item *
+
+C<self.id> - C<id> is the name of the column in I<this> table
+that is referenced by the foreign key.
+
+=back
+
+See L<DBIx::Class::Relationship/has_many> for
+additional information.  Note that you might see a "hand coded"
+version of the C<has_many> relationship above expressed as:
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      "book_id",
+    );
+
+Where the third argument is simply the name of the column in
+the foreign table.  However, the hashref syntax used by 
+L<DBIx::Class::Schema::Loader> is more flexible (for example,
+it can handle "multi-column" foreign keys).
+
+B<Note:> If you are using older versions of SQLite and related DBIC 
+tools, you will need to manually define your C<has_many> and 
+C<belongs_to> relationships. We recommend upgrading to the versions 
+specified above. :-) 
+
+Have a look at C<lib/MyApp/Schema/Result/BookAuthor.pm> and notice
+that there is a C<belongs_to> relationship defined that acts as the
+"mirror image" to the C<has_many> relationship we just looked at
+above:
+
+    =head1 RELATIONS
+
+    =head2 book
+
+    Type: belongs_to
+
+    Related object: L<MyApp::Schema::Result::Book>
+
+    =cut
+
+    __PACKAGE__->belongs_to(
+      "book",
+      "MyApp::Schema::Result::Book",
+      { id => "book_id" },
+      { join_type => "LEFT" },
+    );
+
+The arguments are similar, but see 
+L<DBIx::Class::Relationship/belongs_to> for the details.
+
+Although recent versions of SQLite and L<DBIx::Class::Schema::Loader> 
+automatically handle the C<has_many> and C<belongs_to> relationships, 
+C<many_to_many> relationships currently need to be manually inserted. 
+To add a C<many_to_many> relationship, first edit 
+C<lib/MyApp/Schema/Result/Book.pm> and add the following text below 
+the C<# You can replace this text...> comment:
 
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_authors => 'MyApp::Schema::Result::BookAuthor', 'book_id');
-    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -1198,15 +1302,13 @@ following text below the C<# You can replace this text...> comment:
     #   You must already have the has_many() defined to use a many_to_many().
     __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
 
-
 B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
 file.  As with any Perl package, we need to end the last line with
 a statement that evaluates to C<true>.  This is customarily done with
 C<1;> on a line by itself.
 
-This code defines both a C<has_many> and a C<many_to_many> 
-relationship. The C<many_to_many> relationship is optional, but it 
-makes it easier to map a book to its collection of authors.  Without 
+The C<many_to_many> relationship is optional, but it makes it
+easier to map a book to its collection of authors.  Without 
 it, we would have to "walk" though the C<book_author> table as in 
 C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we 
 will see examples on how to use DBIx::Class objects in your code soon, 
@@ -1217,21 +1319,11 @@ C<$book-E<gt>author-E<gt>first-E<gt>last_name>. Note that you cannot
 define a C<many_to_many> relationship without also having the 
 C<has_many> relationship in place.
 
-Then edit C<lib/MyApp/Schema/Result/Author.pm> and add relationship
-information as follows (again, be careful to put in above the C<1;> but
-below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
+Then edit C<lib/MyApp/Schema/Result/Author.pm> and add the reverse 
+C<many_to_many> relationship for C<Author> as follows (again, be careful 
+to put in above the C<1;> but below the C<# DO NOT MODIFY THIS OR 
+ANYTHING ABOVE!> comment): 
 
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create an accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_authors => 'MyApp::Schema::Result::BookAuthor', 'author_id');
-    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -1240,43 +1332,21 @@ below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
     #   You must already have the has_many() defined to use a many_to_many().
     __PACKAGE__->many_to_many(books => 'book_authors', 'book');
 
-Finally, do the same for the "join table,"
-C<lib/MyApp/Schema/Result/BookAuthor.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(book => 'MyApp::Schema::Result::Book', 'book_id');
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
-
 
 =head2 Run The Application
 
 Run the Catalyst development server script with the C<DBIC_TRACE> option
 (it might still be enabled from earlier in the tutorial, but here is an
-alternate way to specify the option just in case):
+alternate way to specify the trace option just in case):
 
-    $ DBIC_TRACE=1 script/myapp_server.pl
+    $ DBIC_TRACE=1 script/myapp_server.pl -r
 
 Make sure that the application loads correctly and that you see the
 three dynamically created model class (one for each of the
 Result Classes we created).
 
 Then hit the URL L<http://localhost:3000/books/list> with your browser 
-and be sure that the book list still displays correctly. You can leave 
-the development server running for the next step if you wish.
+and be sure that the book list still displays correctly.
 
 B<Note:> You will not see the authors yet because the view does not yet 
 use the new relations. Read on to the next section where we update the 
@@ -1435,8 +1505,8 @@ detailed information on how to extend C<RenderView> in C<sub end>.
 One of the nice features of C<RenderView> is that it automatically 
 allows you to add C<dump_info=1> to the end of any URL for your 
 application and it will force the display of the "exception dump" 
-screen to the client browser.  You can try this out by starting the 
-development server as before and then point your browser to this URL: 
+screen to the client browser.  You can try this out by pointing 
+your browser to this URL: 
 
     http://localhost:3000/books/list?dump_info=1
 
@@ -1477,7 +1547,7 @@ has changed):
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
@@ -1485,18 +1555,17 @@ has changed):
     
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
+        $c->stash(books => [$c->model('DB::Book')->all]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (actions methods respond to user input in
         # your controllers).
-        #$c->stash->{template} = 'books/list.tt2';
+        #$c->stash(template => 'books/list.tt2');
     }
 
 
-You should now be able to restart the development server as per the
-previous section and access the L<http://localhost:3000/books/list>
-as before.
+You should now be able to access the L<http://localhost:3000/books/list>
+URL as before.
 
 B<NOTE:> Please note that if you use the default template technique,
 you will B<not> be able to use either the C<$c-E<gt>forward> or
@@ -1513,14 +1582,13 @@ In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
 later in the tutorial, you should remove the comment from the
 statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
 
-    $c->stash->{template} = 'books/list.tt2';
+    $c->stash(template => 'books/list.tt2');
 
 Then delete the C<TEMPLATE_EXTENSION> line in
 C<lib/MyApp/View/TT.pm>.
 
-You should then be able to restart the development server and
-access L<http://localhost:3000/books/list> in the same manner as
-with earlier sections.
+Check the L<http://localhost:3000/books/list> URL in your browser.
+It should look the same manner as with earlier sections.
 
 
 =head1 AUTHOR
@@ -68,8 +68,8 @@ functionality, will be addressed in Chapter 9.
 
 Although this chapter of the tutorial will show you how to build CRUD 
 functionality yourself, another option is to use a "CRUD builder" type 
-of tool to automate the process.  You get less control, but it's quick 
-and easy.  For example, see 
+of tool to automate the process.  You get less control, but it can be 
+quick and easy.  For example, see 
 L<Catalyst::Plugin::AutoCRUD|Catalyst::Plugin::AutoCRUD>, 
 L<CatalystX::CRUD|CatalystX::CRUD>, and 
 L<CatalystX::CRUD::YUI|CatalystX::CRUD::YUI>.
@@ -96,7 +96,7 @@ Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
     
     =cut
     
-    sub url_create : Local {
+    sub url_create :Local {
         # In addition to self & context, get the title, rating, &
         # author_id args from the URL.  Note that Catalyst automatically
         # puts extra information after the "/<controller_name>/<action_name/"
@@ -116,11 +116,9 @@ Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
     
-        # Assign the Book object to the stash for display in the view
-        $c->stash->{book} = $book;
-    
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
+        # Assign the Book object to the stash for display and set template
+        $c->stash(book     => $book,
+                  template => 'books/create_done.tt2');
     }
 
 Notice that Catalyst takes "extra slash-separated information" from the
@@ -183,7 +181,7 @@ outputs the "last name for the first author" above to match this:
 
 to get around an issue in TT v2.15 where blessed hash objects were not 
 handled correctly.  But, if you are still using v2.15, it's probably 
-time to upgrade  (v2.15 is 3.5+ years old).  If you are following 
+time to upgrade  (v2.15 is almost 4 years old).  If you are following 
 along in Debian, then you should be on at least v2.20.  You can test 
 your version of Template Toolkit with the following:
 
@@ -192,21 +190,14 @@ your version of Template Toolkit with the following:
 
 =head2 Try the 'url_create' Feature
 
-If the application is still running from before, use C<Ctrl-C> to kill
-it. Then restart the server:
+Make sure the development server is running with the "-r" restart
+option:
 
-    $ DBIC_TRACE=1 script/myapp_server.pl
+    $ DBIC_TRACE=1 script/myapp_server.pl -r
 
 Note that new path for C</books/url_create> appears in the startup debug
 output.
 
-B<TIP>: You can use C<script/myapp_server.pl -r> to have the development
-server auto-detect changed files and reload itself (if your browser acts
-odd, you should also try throwing in a C<-k>).  If you make changes to
-the TT templates only, you do not need to reload the development server
-(only changes to "compiled code" such as Controller and Model C<.pm>
-files require a reload).
-
 Next, use your browser to enter the following URL:
 
     http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
@@ -366,9 +357,8 @@ to the following:
     | /books/url_create                   | /books/url_create                    |
     '-------------------------------------+--------------------------------------'
 
-Now start the development server with our basic chained method in
-place and the startup debug output should change to something along
-the lines of the following:
+When the development server restarts, the debug output should change 
+to something along the lines of the following:
 
     [debug] Loaded Path actions:
     .-------------------------------------+--------------------------------------.
@@ -420,7 +410,7 @@ method:
         my ($self, $c) = @_;
     
         # Store the ResultSet in stash so it's available for other methods
-        $c->stash->{resultset} = $c->model('DB::Book');
+        $c->stash(resultset => $c->model('DB::Book'));
     
         # Print a message to the debug log
         $c->log->debug('*** INSIDE BASE METHOD ***');
@@ -443,9 +433,9 @@ C<url_create> to match the following:
 
     sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
 
-Next, try out the refactored chain by restarting the development
-server.  Notice that our "Loaded Chained actions" section has changed
-slightly:
+Once you save C<lib/MyApp/Controller/Books.pm>, notice that the 
+development server will restart and our "Loaded Chained actions" section 
+will changed slightly:
 
     [debug] Loaded Chained actions:
     .-------------------------------------+--------------------------------------.
@@ -502,7 +492,7 @@ Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
         my ($self, $c) = @_;
     
         # Set the TT template to use
-        $c->stash->{template} = 'books/form_create.tt2';
+        $c->stash(template => 'books/form_create.tt2');
     }
 
 This action simply invokes a view containing a form to create a book.
@@ -556,25 +546,18 @@ save the form information to the database:
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
     
-        # Store new model object in stash
-        $c->stash->{book} = $book;
-    
         # Avoid Data::Dumper issue mentioned earlier
         # You can probably omit this
         $Data::Dumper::Useperl = 1;
     
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
+        # Store new model object in stash and set template
+        $c->stash(book     => $book,
+                  template => 'books/create_done.tt2');
     }
 
 
 =head2 Test Out The Form
 
-If the application is still running from before, use C<Ctrl-C> to kill
-it.  Then restart the server:
-
-    $ script/myapp_server.pl
-
 Notice that the server startup log reflects the two new chained
 methods that we added:
 
@@ -735,22 +718,6 @@ Now, any other method that chains off C<object> will automatically
 have the appropriate book waiting for it in
 C<$c-E<gt>stash-E<gt>{object}>.
 
-Also note that we are using a different technique for setting
-C<$c-E<gt>stash>.  The advantage of this style is that it lets you set
-multiple stash variables at a time.  For example:
-
-    $c->stash(object => $c->stash->{resultset}->find($id),
-              another_thing => 1);
-
-or as a hashref:
-
-    $c->stash({object => $c->stash->{resultset}->find($id),
-              another_thing => 1});
-
-Either format works, but the C<$c-E<gt>stash(name =E<gt> value);>
-style is growing in popularity -- you may wish to use it all
-the time (even when you are only setting a single value).
-
 
 =head2 Add a Delete Action to the Controller
 
@@ -794,12 +761,8 @@ equivalent.
 
 =head2 Try the Delete Feature
 
-If the application is still running from before, use C<Ctrl-C> to kill
-it.  Then restart the server:
-
-    $ DBIC_TRACE=1 script/myapp_server.pl
-
-The C<delete> method now appears in the "Loaded Chained actions" section
+One you save the Books controller, the server should automatically restart.
+The C<delete> method should now appear in the "Loaded Chained actions" section
 of the startup debug output:
 
     [debug] Loaded Chained actions:
@@ -877,16 +840,15 @@ C<sub delete> method to match:
 
 =head2 Try the Delete and Redirect Logic
 
-Restart the development server and point your browser to
-L<http://localhost:3000/books/list> (don't just hit "Refresh" in your
-browser since we left the URL in an invalid state in the previous
-section!) and delete the first copy of the remaining two
-"TCPIP_Illustrated_Vol-2" books.  The URL in your browser should return
-to the L<http://localhost:3000/books/list> URL, so that is an
-improvement, but notice that I<no green "Book deleted" status message is
-displayed>.  Because the stash is reset on every request (and a redirect
-involves a second request), the C<status_msg> is cleared before it can
-be displayed.
+Point your browser to L<http://localhost:3000/books/list> (don't just 
+hit "Refresh" in your browser since we left the URL in an invalid state 
+in the previous section!) and delete the first copy of the remaining two 
+"TCPIP_Illustrated_Vol-2" books. The URL in your browser should return 
+to the L<http://localhost:3000/books/list> URL, so that is an 
+improvement, but notice that I<no green "Book deleted" status message is 
+displayed>. Because the stash is reset on every request (and a redirect 
+involves a second request), the C<status_msg> is cleared before it can 
+be displayed. 
 
 
 =head2 Using 'uri_for' to Pass Query Parameters
@@ -939,11 +901,13 @@ C<E<lt>span class="message"E<gt>> line.
 
 =head2 Try the Delete and Redirect With Query Param Logic
 
-Restart the development server and point your browser to
-L<http://localhost:3000/books/list> (you should now be able to safely
-hit "refresh" in your browser).  Then delete the remaining copy of
-"TCPIP_Illustrated_Vol-2".  The green "Book deleted" status message
-should return.
+Point your browser to L<http://localhost:3000/books/list> (you should 
+now be able to safely hit "refresh" in your browser). Then delete the 
+remaining copy of "TCPIP_Illustrated_Vol-2". The green "Book deleted" 
+status message should return.  But notice that you can now hit the
+"Reload" button in your browser and it just redisplays the book
+list (and it correctly shows it without the "Book deleted" message
+on redisplay).
 
 B<NOTE:> Another popular method for maintaining server-side
 information across a redirect is to use the C<flash> technique we
@@ -978,12 +942,12 @@ each book was added and when each book is updated:
     sqlite> ALTER TABLE book ADD updated INTEGER;
     sqlite> UPDATE book SET created = DATETIME('NOW'), updated = DATETIME('NOW');
     sqlite> SELECT * FROM book;
-    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
-    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    1|CCSP SNRS Exam Certification Guide|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    2|TCP/IP Illustrated, Volume 1|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    3|Internetworking with TCP/IP Vol.1|4|2010-02-16 04:15:45|2010-02-16 04:15:45
+    4|Perl Cookbook|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    5|Designing with Web Standards|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    9|TCP/IP Illustrated, Vol 3|5|2010-02-16 04:15:45|2010-02-16 04:15:45
     sqlite> .quit
     $
 
@@ -997,7 +961,8 @@ Next, we should re-run the DBIC helper to update the Result Classes
 with the new fields:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
+        create=static components=TimeStamp dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
      exists "/root/dev/MyApp/script/../lib/MyApp/Model"
      exists "/root/dev/MyApp/script/../t"
     Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
@@ -1008,10 +973,11 @@ Notice that we modified our use of the helper slightly: we told
 it to include the L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp>
 in the C<load_components> line of the Result Classes.
 
-If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you
-should see that the C<created> and C<updated> fields are now included
-in the call to C<add_columns()>, but our relationship information below
-the "C<# DO NOT MODIFY...>" line was automatically preserved.
+If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you should 
+see that the C<created> and C<updated> fields are now included in the 
+call to C<add_columns()>. However, also notice that the C<many_to_many> 
+relationships we manually added below the "C<# DO NOT MODIFY...>" line 
+were automatically preserved. 
 
 While we have this file open, let's update it with some additional
 information to have DBIC automatically handle the updating of these
@@ -1035,11 +1001,6 @@ C<set_on_update> options will cause DBIx::Class to automatically
 update the timestamps in these columns whenever a row is created or 
 modified.
 
-To test this out, restart the development server using the
-C<DBIC_TRACE=1> option:
-
-    DBIC_TRACE=1 script/myapp_server.pl
-
 Then enter the following URL into your web browser:
 
     http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
@@ -1050,19 +1011,20 @@ you will see that the new book we added has an appropriate date and
 time entered for it (see the last line in the listing below):
 
     $ sqlite3 myapp.db "select * from book"
-    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
-    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    10|TCPIP_Illustrated_Vol-2|5|2009-03-08 16:29:08|2009-03-08 16:29:08
+    1|CCSP SNRS Exam Certification Guide|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    2|TCP/IP Illustrated, Volume 1|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    3|Internetworking with TCP/IP Vol.1|4|2010-02-16 04:15:45|2010-02-16 04:15:45
+    4|Perl Cookbook|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    5|Designing with Web Standards|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    9|TCP/IP Illustrated, Vol 3|5|2010-02-16 04:15:45|2010-02-16 04:15:45
+    10|TCPIP_Illustrated_Vol-2|5|2010-02-16 04:18:42|2010-02-16 04:18:42
+    sqlite> .q
 
 Notice in the debug log that the SQL DBIC generated has changed to
 incorporate the datetime logic:
 
     INSERT INTO book ( created, rating, title, updated ) VALUES ( ?, ?, ?, ? ): 
-    '2009-05-25 20:39:41', '5', 'TCPIP_Illustrated_Vol-2', '2009-05-25 20:39:41'
+    '2010-02-16 04:18:42', '5', 'TCPIP_Illustrated_Vol-2', '2010-02-16 04:18:42'
     INSERT INTO book_author ( author_id, book_id ) VALUES ( ?, ? ): '4', '10'
 
 
@@ -1099,7 +1061,7 @@ Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
     sub created_after {
         my ($self, $datetime) = @_;
     
-        my $date_str = $self->_source_handle->schema->storage
+        my $date_str = $self->result_source->schema->storage
                               ->datetime_parser->format_datetime($datetime);
     
         return $self->search({
@@ -1109,15 +1071,6 @@ Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
     
     1;
 
-Then we need to tell the Result Class to to treat this as a ResultSet
-Class.  Open C<lib/MyApp/Schema/Result/Book.pm> and add the following
-above the "C<1;>" at the bottom of the file:
-
-    #
-    # Set ResultSet Class
-    #
-    __PACKAGE__->resultset_class('MyApp::Schema::ResultSet::Book');
-
 Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
 
     =head2 list_recent
@@ -1132,24 +1085,24 @@ Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
-        $c->stash->{books} = [$c->model('DB::Book')
-                                ->created_after(DateTime->now->subtract(minutes => $mins))];
+        $c->stash(books => [$c->model('DB::Book')
+                                ->created_after(DateTime->now->subtract(minutes => $mins))]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
-Now start the development server with C<DBIC_TRACE=1> and try
-different values for the minutes argument (the final number value) for
-the URL C<http://localhost:3000/books/list_recent/10>.  For example,
-this would list all books added in the last fifteen minutes:
+Now try different values for the "minutes" argument (the final number 
+value) using the URL C<http://localhost:3000/books/list_recent/_#_> in 
+your browser. For example, this would list all books added in the last 
+fifteen minutes: 
 
     http://localhost:3000/books/list_recent/15
 
 Depending on how recently you added books, you might want to
-try a higher or lower value.
+try a higher or lower value for the minutes.
 
 
 =head2 Chaining ResultSets
@@ -1182,22 +1135,18 @@ C<lib/MyApp/Controller/Books.pm> and add the following method:
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
         # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
+        $c->stash(books => [$c->model('DB::Book')
                                 ->created_after(DateTime->now->subtract(minutes => $mins))
                                 ->search({title => {'like', '%TCP%'}})
-                             ];
+                            ]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
-To try this out, restart the development server with:
-
-    DBIC_TRACE=1 script/myapp_server.pl
-
-And enter the following URL into your browser:
+To try this out, enter the following URL into your browser:
 
     http://localhost:3000/books/list_recent_tcp/100
 
@@ -1213,7 +1162,7 @@ Take a look at the DBIC_TRACE output in the development server log for
 the first URL and you should see something similar to the following:
 
     SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me 
-    WHERE ( ( title LIKE ? AND created > ? ) ): '%TCP%', '2009-05-25 19:09:13'
+    WHERE ( ( title LIKE ? AND created > ? ) ): '%TCP%', '2010-02-16 02:49:32'
 
 However, let's not pollute our controller code with this raw "TCP"
 query -- it would be cleaner to encapsulate that code in a method on
@@ -1253,21 +1202,20 @@ shown here -- the rest of the method should be the same):
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
         # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
+        $c->stash(books => [$c->model('DB::Book')
                                 ->created_after(DateTime->now->subtract(minutes => $mins))
                                 ->title_like('TCP')
-                             ];
+                            ]);
     
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
+        $c->stash(template => 'books/list.tt2');
     }
 
-Then restart the development server and try out the C<list_recent_tcp>
-and C<list_recent> URL as we did above.  It should work just the same,
-but our code is obviously cleaner and more modular, while also being
-more flexible at the same time.
+Try out the C<list_recent_tcp> and C<list_recent> URLs as we did above. 
+They should work just the same, but our code is obviously cleaner and 
+more modular, while also being more flexible at the same time. 
 
 
 =head2 Adding Methods to Result Classes
@@ -1284,7 +1232,7 @@ C<lib/MyApp/Schema/Result/Author.pm> and add the following method (as
 always, it must be above the closing "C<1;>"):
 
     #
-    # Helper methods
+    # Row-level helper methods
     #
     sub full_name {
         my ($self) = @_;
@@ -1311,8 +1259,7 @@ to:
 (Only C<author.last_name> was changed to C<author.full_name> -- the
 rest of the file should remain the same.)
 
-Now restart the development server and go to the standard book list
-URL:
+Now go to the standard book list URL:
 
     http://localhost:3000/books/list
 
@@ -1409,13 +1356,13 @@ match the following:
     ...
 
 Although most of the code we removed comprised comments, the overall 
-effect is dramatic... because our view code is so simple, we don't 
-huge comments to clue people in to the gist of our code.  The view 
-code is now self-documenting and readable enough that you could 
-probably get by with no comments at all.  All of the "complex" work is 
-being done in our Result Class methods (and, because we have broken 
-the code into nice, modular chucks, the Result Class code is hardly 
-something you would call complex).  
+effect is dramatic... because our view code is so simple, we don't need 
+huge comments to clue people in to the gist of our code. The view code 
+is now self-documenting and readable enough that you could probably get 
+by with no comments at all. All of the "complex" work is being done in 
+our Result Class methods (and, because we have broken the code into 
+nice, modular chucks, the Result Class code is hardly something you 
+would call complex).
 
 As we saw in this section, always strive to keep your view AND 
 controller code as simple as possible by pulling code out into your 
@@ -1424,9 +1371,9 @@ ways, it's an excellent to way accomplish this objective.  It will
 make your code cleaner, easier to write, less error-prone, and easier 
 to debug and maintain.
 
-Before you conclude this section, fire up the development server and
-hit Refresh in your browser... the output should be the same even
-though the backend code has been trimmed down.
+Before you conclude this section, hit Refresh in your browser... the 
+output should be the same even though the backend code has been trimmed 
+down. 
 
 
 =head1 AUTHOR
@@ -84,6 +84,7 @@ C<myapp02.sql> in your editor and insert:
     --
     -- Add user and role tables, along with a many-to-many join table
     --
+    PRAGMA foreign_keys = ON;
     CREATE TABLE user (
             id            INTEGER PRIMARY KEY,
             username      TEXT,
@@ -98,8 +99,8 @@ C<myapp02.sql> in your editor and insert:
             role TEXT
     );
     CREATE TABLE user_role (
-            user_id INTEGER,
-            role_id INTEGER,
+            user_id INTEGER REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE,
+            role_id INTEGER REFERENCES role(id) ON DELETE CASCADE ON UPDATE CASCADE,
             PRIMARY KEY (user_id, role_id)
     );
     --
@@ -127,7 +128,8 @@ the new tables added in the previous step, let's use the C<create=static>
 option on the DBIC model helper to do most of the work for us:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
+        create=static components=TimeStamp dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
      exists "/root/dev/MyApp/script/../lib/MyApp/Model"
      exists "/root/dev/MyApp/script/../t"
     Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
@@ -137,77 +139,41 @@ option on the DBIC model helper to do most of the work for us:
     $ ls lib/MyApp/Schema/Result
     Author.pm  BookAuthor.pm  Book.pm  Role.pm  User.pm  UserRole.pm
 
-Notice how the helper has added three new table-specific result source
+Notice how the helper has added three new table-specific Result Source
 files to the C<lib/MyApp/Schema/Result> directory.  And, more
 importantly, even if there were changes to the existing result source
 files, those changes would have only been written above the C<# DO NOT
 MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited
 enhancements would have been preserved.
 
-Speaking of "hand-editted enhancements," we should now add
-relationship information to the three new result source files.  Edit
-each of these files and add the following information between the C<#
-DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
+Speaking of "hand-editted enhancements," we should now add the 
+C<many_to_many> relationship information to the User Result Source file. 
+As with the Book, BookAuthor, and Author files in 
+L<Chapter 3|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>, 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> has 
+automatically created the C<has_many> and C<belongs_to> relationships 
+for the new User, UserRole, and Role tables. However, as a convenience 
+for mapping Users to their assigned roles (see 
+L<Chapter 6|Catalyst::Manual::Tutorial::06_Authorization>), we will 
+also manually add a C<many_to_many> relationship. Edit 
+C<lib/MyApp/Schema/Result/User.pm> add the following information between 
+the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing 
+C<1;>: 
 
-C<lib/MyApp/Schema/Result/User.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(map_user_roles => 'MyApp::Schema::Result::UserRole', 'user_id');
-    
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
     #     2) Name of has_many() relationship this many_to_many() is shortcut for
     #     3) Name of belongs_to() relationship in model class of has_many() above
     #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(roles => 'map_user_roles', 'role');
-
+    __PACKAGE__->many_to_many(roles => 'user_roles', 'role');
 
-C<lib/MyApp/Schema/Result/Role.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(map_user_roles => 'MyApp::Schema::Result::UserRole', 'role_id');
-
-
-C<lib/MyApp/Schema/Result/UserRole.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(user => 'MyApp::Schema::Result::User', 'user_id');
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(role => 'MyApp::Schema::Result::Role', 'role_id');
-
-The code for these three sets of updates is obviously very similar to
-the edits we made to the C<Book>, C<Author>, and C<BookAuthor>
-classes created in Chapter 3.
+The code for this update is obviously very similar to the edits we made 
+to the C<Book> and C<Author> classes created in Chapter 3 with one 
+exception: we only defined the C<many_to_many> relationship in one 
+direction. Whereas we felt that we would want to map Authors to Books 
+B<AND> Books to Authors, here we are only adding the convenience 
+C<many_to_many> in the Users to Roles direction. 
 
 Note that we do not need to make any change to the
 C<lib/MyApp/Schema.pm> schema file.  It simply tells DBIC to load all
@@ -216,16 +182,15 @@ C<lib/MyApp/Schema> directory, so it will automatically pick up our
 new table information.
 
 
-=head2 Sanity-Check Reload of Development Server
-
-We aren't ready to try out the authentication just yet; we only want
-to do a quick check to be sure our model loads correctly.  Press
-C<Ctrl-C> to kill the previous server instance (if it's still running)
-and restart it:
-
-    $ script/myapp_server.pl
+=head2 Sanity-Check of the Development Server Reload
 
-Look for the three new model objects in the startup debug output:
+We aren't ready to try out the authentication just yet; we only want to 
+do a quick check to be sure our model loads correctly. Assuming that you 
+are following along and using the "-r" option on C<myapp_server.pl>, 
+then the development server should automatically reload (if not, press 
+C<Ctrl-C> to break out of the server if it's running and then enter 
+C<script/myapp_server.pl> to start it). Look for the three new model 
+objects in the startup debug output: 
 
     ...
      .-------------------------------------------------------------------+----------.
@@ -255,18 +220,18 @@ C<StackTrace> is new):
 
     # Load plugins
     use Catalyst qw/
-                    -Debug
-                    ConfigLoader
-                    Static::Simple
+        -Debug
+        ConfigLoader
+        Static::Simple
     
-                    StackTrace
+        StackTrace
     
-                    Authentication
+        Authentication
     
-                    Session
-                    Session::Store::FastMmap
-                    Session::State::Cookie
-                    /;
+        Session
+        Session::Store::FastMmap
+        Session::State::Cookie
+    /;
 
 B<Note:> As discussed in MoreCatalystBasics, different versions of
 C<Catalyst::Devel> have used a variety of methods to load the plugins,
@@ -287,19 +252,18 @@ configuration (see below).
 Make sure you include the additional plugins as new dependencies in
 the Makefile.PL file something like this:
 
-    requires (
-        'Catalyst::Plugin::Authentication' => '0',
-        'Catalyst::Plugin::Session' => '0',
-        'Catalyst::Plugin::Session::Store::FastMmap' => '0',
-        'Catalyst::Plugin::Session::State::Cookie' => '0',
-    );
+    requires 'Catalyst::Plugin::Authentication';
+    requires 'Catalyst::Plugin::Session';
+    requires 'Catalyst::Plugin::Session::Store::FastMmap';
+    requires 'Catalyst::Plugin::Session::State::Cookie';
 
 Note that there are several options for
-L<Session::Store|Catalyst::Plugin::Session::Store>
-(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
-is generally a good choice if you are on Unix; try
-L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you
-are on Win32) -- consult
+L<Session::Store|Catalyst::Plugin::Session::Store>.
+L<Session::Store::Memcached|Catalyst::Plugin::Session::Store::Memcached> or
+L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap> is
+generally a good choice if you are on Unix.  If you are running on
+Windows, try
+L<Session::Store::File|Catalyst::Plugin::Session::Store::File>. Consult
 L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses
 for additional information and options (for example to use a database-
 backed session store).
@@ -347,11 +311,15 @@ B<TIP:> Here is a short script that will dump the contents of
 C<MyApp->config> to L<Config::General|Config::General> format in
 C<myapp.conf>:
 
-    $ perl -Ilib -e 'use MyApp; use Config::General; 
+    $ CATALYST_DEBUG=0 perl -Ilib -e 'use MyApp; use Config::General; 
         Config::General->new->save_file("myapp.conf", MyApp->config);'
 
+B<HOWEVER>, if you try out the command above, be sure to delete the
+"myapp.conf" command.  Otherwise, you will wind up with duplicate
+configurations.
+
 B<NOTE:> Because we are using SimpleDB along with a database layout 
-that complies with its default assumptions, we don't need to specify
+that complies with its default assumptions: we don't need to specify
 the names of the columns where our username and password information
 is stored (hence, the "Simple" part of "SimpleDB").  That being said,
 SimpleDB lets you specify that type of information if you need to.
@@ -388,11 +356,11 @@ and update the definition of C<sub index> to match:
         my ($self, $c) = @_;
     
         # Get the username and password from form
-        my $username = $c->request->params->{username} || "";
-        my $password = $c->request->params->{password} || "";
+        my $username = $c->request->params->{username};
+        my $password = $c->request->params->{password};
     
         # If the username and password values were found in form
-        if (defined($username) && defined($password)) {
+        if ($username && $password) {
             # Attempt to log the user in
             if ($c->authenticate({ username => $username,
                                    password => $password  } )) {
@@ -402,15 +370,19 @@ and update the definition of C<sub index> to match:
                 return;
             } else {
                 # Set an error message
-                $c->stash->{error_msg} = "Bad username or password.";
+                $c->stash(error_msg => "Bad username or password.");
             }
+        } else {
+            # Set an error message
+            $c->stash(error_msg => "Empty username or password.");
         }
     
         # If either of above don't work out, send to the login page
-        $c->stash->{template} = 'login.tt2';
+        $c->stash(template => 'login.tt2');
     }
 
-Be sure to remove the C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
+Be sure to remove the 
+C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
 line of the C<sub index>.
 
 This controller fetches the C<username> and C<password> values from the
@@ -505,7 +477,7 @@ the following method:
     # Note that 'auto' runs after 'begin' but before your actions and that
     # 'auto's "chain" (all from application path to most specific class are run)
     # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
-    sub auto : Private {
+    sub auto :Private {
         my ($self, $c) = @_;
     
         # Allow unauthenticated users to reach the login page.  This
@@ -579,10 +551,15 @@ use of an IF-THEN-ELSE construct in TT).
 
 =head2 Try Out Authentication
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
+The development server should have reloaded each time we edited one of 
+the Controllers in the previous section. Now trying going to 
+L<http://localhost:3000/books/list> and you should be redirected to the 
+login page, hitting Shift+Reload or Ctrl+Reload if necessary (the "You 
+are already logged in" message should I<not> appear -- if it does, click 
+the C<logout> button and try again). Note the C<***Root::auto User not 
+found...> debug message in the development server output. Enter username 
+C<test01> and password C<mypass>, and you should be taken to the Book 
+List page. 
 
 B<IMPORTANT NOTE:> If you are having issues with authentication on
 Internet Explorer, be sure to check the system clocks on both your
@@ -605,17 +582,10 @@ UDP vs. the more common TCP that you see with most Internet protocols.
 Worse case, you might have to manually set the time on your development
 box instead of using NTP.
 
-Now trying going to L<http://localhost:3000/books/list> and you should
-be redirected to the login page, hitting Shift+Reload or Ctrl+Reload
-if necessary (the "You are already logged in" message should I<not>
-appear -- if it does, click the C<logout> button and try again). Note
-the C<***Root::auto User not found...> debug message in the
-development server output.  Enter username C<test01> and password
-C<mypass>, and you should be taken to the Book List page.
-
 Open C<root/src/books/list.tt2> and add the following lines to the
 bottom (below the closing </table> tag):
 
+    ...
     <p>
       <a href="[% c.uri_for('/login') %]">Login</a>
       <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Create</a>
@@ -623,7 +593,7 @@ bottom (below the closing </table> tag):
 
 Reload your browser and you should now see a "Login" and "Create" links
 at the bottom of the page (as mentioned earlier, you can update template
-files without reloading the development server).  Click the first link
+files without a development server reload).  Click the first link
 to return to the login page.  This time you I<should> see the "You are
 already logged in" message.
 
@@ -659,14 +629,15 @@ saw in Chapters 3 and 4, but add C<,EncodedColumn> to the C<components>
 argument:
 
     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db
+        create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db \
+        on_connect_do="PRAGMA foreign_keys = ON"
 
 If you then open one of the Result Classes, you will see that it 
 includes EncodedColumn in the C<load_components> line.  Take a look at 
 C<lib/MyApp/Schema/Result/User.pm> since that's the main class where we
 want to use hashed and salted passwords:
 
-    __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn", "Core");
+    __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn");
 
 
 =head2 Modify the "password" Column to Use EncodedColumn
@@ -738,7 +709,7 @@ Then run the following command:
 
     $ DBIC_TRACE=1 perl -Ilib set_hashed_passwords.pl
 
-We had to use the C<-Ilib> arguement to tell perl to look under the 
+We had to use the C<-Ilib> argument to tell perl to look under the 
 C<lib> directory for our C<MyApp::Schema> model.
 
 The DBIC_TRACE output should show that the update worked:
@@ -789,14 +760,11 @@ C<check_password> method we enabled on our C<password> columns.
 
 =head2 Try Out the Hashed Passwords
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-You should now be able to go to L<http://localhost:3000/books/list> and
-login as before.  When done, click the "logout" link on the login page
-(or point your browser at L<http://localhost:3000/logout>).
+The development server should restart as soon as your save the 
+C<lib/MyApp.pm> file in the previous section. You should now be able to 
+go to L<http://localhost:3000/books/list> and login as before. When 
+done, click the "logout" link on the login page (or point your browser 
+at L<http://localhost:3000/logout>). 
 
 
 =head1 USING THE SESSION FOR FLASH
@@ -856,7 +824,7 @@ C<< <span class="message"> >> line.
 
 =head2 Try Out Flash
 
-Restart the development server, log in, and then point your browser to
+Authenticate using the login screen and then point your browser to
 L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
 several books.  Click the "Return to list" link and delete one of the
 "Test" books you just added.  The C<flash> mechanism should retain our
@@ -884,7 +852,9 @@ C<__PACKAGE__-E<gt>config> setting to something like:
 
     __PACKAGE__->config(
             name    => 'MyApp',
-            session => {flash_to_stash => 1},
+            # Disable deprecated behavior needed by old applications
+            disable_component_resolution_regex_fallback => 1,
+            session => { flash_to_stash => 1 },
         );
 
 B<or> add the following to C<myapp.conf>:
@@ -902,11 +872,10 @@ to match the following:
 
     <span class="message">[% status_msg %]</span>
 
-Restart the development server and go to
-L<http://localhost:3000/books/list> in your browser.  Delete another
-of the "Test" books you added in the previous step.  Flash should still
-maintain the status message across the redirect even though you are no
-longer explicitly accessing C<c.flash>.
+Now go to L<http://localhost:3000/books/list> in your browser. Delete 
+another of the "Test" books you added in the previous step. Flash should 
+still maintain the status message across the redirect even though you 
+are no longer explicitly accessing C<c.flash>. 
 
 
 =head1 AUTHOR
@@ -80,27 +80,24 @@ Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
 
     # Load plugins
     use Catalyst qw/
-                    -Debug
-                    ConfigLoader
-                    Static::Simple
-                
-                    StackTrace
-                
-                    Authentication
-                    Authorization::Roles
+        -Debug
+        ConfigLoader
+        Static::Simple
         
-                    Session
-                    Session::Store::FastMmap
-                    Session::State::Cookie
-                    /;
+        StackTrace
+        
+        Authentication
+        Authorization::Roles
+        
+        Session
+        Session::Store::FastMmap
+        Session::State::Cookie
+    /;
 
 Once again, include this additional plugin as a new dependency in 
 the Makefile.PL file like this:
 
-    requires (
-        ...
-        'Catalyst::Plugin::Authorization::Roles' => '0',
-    );
+    requires 'Catalyst::Plugin::Authorization::Roles';
 
 
 =head2 Add Role-Specific Logic to the "Book List" Template
@@ -175,11 +172,9 @@ updating C<url_create> to match the following code:
             # Note: Above is a shortcut for this:
             # $book->create_related('book_authors', {author_id => $author_id});
     
-            # Assign the Book object to the stash for display in the view
-            $c->stash->{book} = $book;
-    
-            # Set the TT template to use
-            $c->stash->{template} = 'books/create_done.tt2';
+            # Assign the Book object to the stash and set template
+            $c->stash(book     => $book,
+                      template => 'books/create_done.tt2');
         } else {
             # Provide very simple feedback to the user.
             $c->response->body('Unauthorized!');
@@ -205,10 +200,9 @@ C<sub add : Local {> and C<=end> after the closing C<}>.
 
 =head2 Try Out Authentication And Authorization
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
+Make sure the development server is running:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 Now trying going to L<http://localhost:3000/books/list> and you should 
 be taken to the login page (you might have to C<Shift+Reload> or 
@@ -261,7 +255,7 @@ this method to our Result Class.  Open
 C<lib/MyApp/Schema/Result/User.pm> and add the following method below 
 the "C<DO NOT MODIFY ...>" line:
 
-    =head 2 has_role
+    =head2 has_role
     
     Check if a user has the specified role
     
@@ -317,7 +311,7 @@ C<lib/MyApp/Controller/Root.pm> and add this method:
     sub error_noperms :Chained('/') :PathPart('error_noperms') :Args(0) {
         my ($self, $c) = @_;
     
-        $c->stash->{template} = 'error_noperms.tt2';
+        $c->stash(template => 'error_noperms.tt2');
     }
 
 And also add the template file by putting the following text into
@@ -325,10 +319,6 @@ C<root/src/error_noperms.tt2>:
 
     <span class="error">Permission Denied</span>
 
-Then run the Catalyst development server script:
-
-    $ script/myapp_server.pl
-
 Log in as C<test01> and create several new books using the C<url_create>
 feature:
 
@@ -118,14 +118,14 @@ C<DB::single=1> line as follows inside the C<list> method (I like to
 "left-justify" my debug statements so I don't forget to remove them, but
 you can obviously indent them if you prefer):
 
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
     
     $DB::single=1;
-            
+    
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
         $c->stash->{books} = [$c->model('DB::Book')->all];
@@ -79,7 +79,7 @@ C<perl Makefile.PL> and C<make test>), but one of the easiest is with the
 C<prove> command.  For example, to run all of the tests in the C<t>
 directory, enter:
 
-    $ prove --lib lib t
+    $ prove -wl t
 
 There will be a lot of output because we have the C<-Debug> flag 
 enabled in C<lib/MyApp.pm> (see the C<CATALYST_DEBUG=0> tip below for 
@@ -130,37 +130,14 @@ Although you can edit the C<lib/MyApp.pm> to comment out the C<-Debug>
 plugin, it's generally easier to simply set the C<CATALYST_DEBUG=0>
 environment variable.  For example:
 
-    $ CATALYST_DEBUG=0 prove --lib lib t
-
-B<Note:> Depending on the versions of various modules you have 
-installed, you might get some C<used only once> warnings -- you can 
-ignore these.  If you want to eliminate the warnings, you can 
-edit C<Template::Base> to disable and then re-enable warnings
-are the C</usr/lib/perl5/Template/Base.pm> line in C<sub new>.
-You can locate where C<Template::Base> is located with the 
-following command (it's probably in a place similar to
-C</usr/lib/perl5/Template/Base.pm>):
-
-    perldoc -l Template::Base
-
-Edit the file and modify C<sub new> to match:
-
-    ...
-    {   no strict qw( refs );
-        # Disable warnings
-        no warnings;
-        $argnames = \@{"$class\::BASEARGS"} || [ ];
-        # Turn warnings back on
-        use warnings;
-    }
-    ...
+    $ CATALYST_DEBUG=0 prove -wl t
 
 During the C<t/02pod> and C<t/03podcoverage> tests, you might notice the
 C<all skipped: set TEST_POD to enable this test> warning message.  To
 execute the Pod-related tests, add C<TEST_POD=1> to the C<prove>
 command:
 
-    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib t
+    $ CATALYST_DEBUG=0 TEST_POD=1 prove -wl t
 
 If you omitted the Pod comments from any of the methods that were
 inserted, you might have to go back and fix them to get these tests to
@@ -169,7 +146,7 @@ pass. :-)
 Another useful option is the C<verbose> (C<-v>) option to C<prove>.  It
 prints the name of each test case as it is being run:
 
-    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib -v t
+    $ CATALYST_DEBUG=0 TEST_POD=1 prove -vwl t
 
 
 =head1 RUNNING A SINGLE TEST
@@ -177,12 +154,12 @@ prints the name of each test case as it is being run:
 You can also run a single script by appending its name to the C<prove>
 command. For example:
 
-    $ CATALYST_DEBUG=0 prove --lib lib t/01app.t
+    $ CATALYST_DEBUG=0 prove -wl t/01app.t
 
 Also note that you can also run tests directly from Perl without C<prove>.
 For example:
 
-    $ CATALYST_DEBUG=0 perl -Ilib t/01app.t
+    $ CATALYST_DEBUG=0 perl -w -Ilib t/01app.t
 
 
 =head1 ADDING YOUR OWN TEST SCRIPT
@@ -205,13 +182,7 @@ editor and enter the following:
     
     use strict;
     use warnings;
-    
-    # Load testing framework and use 'no_plan' to dynamically pick up
-    # all tests. Better to replace "'no_plan'" with "tests => 30" so it
-    # knows exactly how many tests need to be run (and will tell you if
-    # not), but 'no_plan' is nice for quick & dirty tests
-    
-    use Test::More 'no_plan';
+    use Test::More;
     
     # Need to specify the name of your app as arg on next line
     # Can also do:
@@ -305,6 +276,8 @@ editor and enter the following:
     # User 'test02' should not be able to add a book
     $ua2->get_ok("http://localhost/books/url_create/TestTitle2/2/5", "'test02' add");
     $ua2->content_contains("Unauthorized!", "Check 'test02' cannot add");
+    
+    done_testing;
 
 The C<live_app.t> test cases uses copious comments to explain each step
 of the process.  In addition to the techniques shown here, there are a
@@ -324,11 +297,11 @@ template).
 
 To run the new test script, use a command such as:
 
-    $ CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
+    $ CATALYST_DEBUG=0 prove -vwl t/live_app01.t
 
 or
 
-    $ DBIC_TRACE=0 CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
+    $ DBIC_TRACE=0 CATALYST_DEBUG=0 prove -vwl t/live_app01.t
 
 Experiment with the C<DBIC_TRACE>, C<CATALYST_DEBUG> and C<-v> 
 settings.  If you find that there are errors, use the techniques 
@@ -384,15 +357,19 @@ change the C<__PACKAGE__-E<gt>config(...> declaration to resemble:
     my $dsn = $ENV{MYAPP_DSN} ||= 'dbi:SQLite:myapp.db';
     __PACKAGE__->config(
         schema_class => 'MyApp::Schema',
-        connect_info => [
-            $dsn,
-        ],
+    
+        connect_info => {
+            dsn => $dsn,
+            user => '',
+            password => '',
+            on_connect_do => q{PRAGMA foreign_keys = ON},
+        }
     );
 
 Then, when you run your test case, you can use commands such as:
 
     $ cp myapp.db myappTEST.db
-    $ CATALYST_DEBUG=0 MYAPP_DSN="dbi:SQLite:myappTEST.db" prove --lib lib -v t/live_app01.t
+    $ CATALYST_DEBUG=0 MYAPP_DSN="dbi:SQLite:myappTEST.db" prove -vwl t/live_app01.t
 
 This will modify the DSN only while the test case is running.  If you
 launch your normal application without the C<MYAPP_DSN> environment
@@ -77,14 +77,19 @@ add additional functionality to the manually created form from Chapter 4.
 
 First, change your C<lib/MyApp/Controller/Books.pm> to inherit from
 L<Catalyst::Controller::HTML::FormFu|Catalyst::Controller::HTML::FormFu>
-by changing the C<use parent> line from the default of:
+by changing the C<extends> line from the default of:
 
-    use parent 'Catalyst::Controller';
+    BEGIN {extends 'Catalyst::Controller'; }
 
 to use the FormFu base controller class:
 
-    use parent 'Catalyst::Controller::HTML::FormFu';
+    BEGIN {extends 'Catalyst::Controller::HTML::FormFu'; }
 
+Don't forget to add:
+
+    requires 'Catalyst::Controller::HTML::FormFu';
+
+to your C<Makefile.PL>.
 
 =head2 Add Action to Display and Save the Form
 
@@ -131,7 +136,7 @@ following method:
         }
         
         # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
+        $c->stash(template => 'books/formfu_create.tt2');
     }
 
 
@@ -219,7 +224,8 @@ Open C<root/src/books/formfu_create.tt2> in your editor and enter the following:
     [%# Render the HTML::FormFu Form %]
     [% form %]
     
-    <p><a href="[% c.uri_for(c.controller.action_for('list')) %]">Return to book list</a></p>
+    <p><a href="[% c.uri_for(c.controller.action_for('list')) 
+        %]">Return to book list</a></p>
 
 
 =head2 Add Links for Create and Update via C<HTML::FormFu>
@@ -239,19 +245,18 @@ use to easily launch our HTML::FormFu-based form.
 
 =head2 Test The HTML::FormFu Create Form
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
+Make sure the server is running with the "-r" restart option:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 Login as C<test01> (password: mypass).  Once at the Book List page,
 click the new HTML::FormFu "Create" link at the bottom to display the
 form.  Fill in the following values:
 
-Title:  Internetworking with TCP/IP Vol. II
-Rating: 4
-Author: Comer
-    
+    Title:  Internetworking with TCP/IP Vol. II
+    Rating: 4
+    Author: Comer
+
 Click the Submit button, and you will be returned to the Book List page
 with a "Book created" status message displayed.
 
@@ -402,11 +407,6 @@ for more filter options.
 
 =head2 Try Out the Updated Form
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
 Make sure you are still logged in as C<test01> and try adding a book 
 with various errors: title less than 5 characters, non-numeric rating, a 
 rating of 0 or 6, etc.  Also try selecting one, two, and zero authors. 
@@ -473,7 +473,7 @@ bottom:
         }
     
         # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
+        $c->stash(template => 'books/formfu_create.tt2');
     }
 
 Most of this code should look familiar to what we used in the 
@@ -539,11 +539,6 @@ existing C<delete> link.
 
 =head2 Try Out the Edit/Update Feature
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
 Make sure you are still logged in as C<test01> and go to the 
 L<http://localhost:3000/books/list> URL in your browser.  Click the 
 "Edit" link next to "Internetworking with TCP/IP Vol. II", change the 
@@ -585,7 +580,7 @@ Or you can proceed to write your own application, which is probably the
 real reason you worked through this Tutorial in the first place.
 
 
-=head2  Config::General Config for this tutorial
+=head2 Config::General Config for this tutorial
 
 If you are having difficulty with YAML config above, please save the
 below into the file C<formfu_create.conf> and delete the
@@ -77,6 +77,11 @@ from CPAN:
 
 It will install L<HTML::FormHandler> as a prereq. 
 
+Also add:
+
+    requires 'HTML::FormHandler::Model::DBIC';
+
+to your C<Makefile.PL>.
 
 =head1 HTML::FormHandler FORM CREATION
 
@@ -94,6 +99,7 @@ to a form is only a couple of lines of code.
 Create the directory C<lib/MyApp/Form>. Create C<lib/MyApp/Form/Book.pm>:
 
     package MyApp::Form::Book;
+
     use HTML::FormHandler::Moose;
     extends 'HTML::FormHandler::Model::DBIC';
     use namespace::autoclean;
@@ -218,7 +224,8 @@ The 'authors' relationship is a 'many-to-many' pseudo-relation, so this field
 can be set to Multiple to allow the selection of multiple authors and make it
 required:
 
-   has_field 'authors' => ( type => 'Multiple', required => 1 );
+   has_field 'authors' => ( type => 'Multiple', label_column => 'last_name',
+                            required => 1 );
 
 Note: FormHandler automatically strips whitespace at the beginning or end of fields.
 If you want some other kind of stripping (or none) you can specify it explicitly.
@@ -712,11 +712,13 @@ tutorial.  As of the most recent release, this include: Florian
 Ragwitz, Mauro Andreolini, Jim Howard, Giovanni Gigante, William 
 Moreno,  Bryan Roach, Ashley Berlin, David Kamholz, Kevin Old, Henning 
 Sprang, Jeremy Jones, David Kurtz, Ingo Wichmann, Shlomi Fish, Murray 
-Walker and Adam Witney.  Thanks to Devin Austin for coming up with an 
-initial version of a non-TTSite wrapper page.  Also, a huge thank you 
-to Kiffin Gish for all the hard work on the "database depluralization" 
-effort!  I'm sure I am missing some names here... apologies for that 
-(please let me know if you name should be here).
+Walker, Adam Witney and xenoterracide.  Thanks to Devin Austin for 
+coming up with an initial version of a non-TTSite wrapper page.  
+Also, a huge thank you to Kiffin Gish for all the hard work on the 
+"database depluralization" effort and Rafael Kitover for the work on 
+updating the tutorial to include foreign key support for SQLite.  
+I'm sure I am missing some names here... apologies for that (please 
+let me know if you name should be here).
 
 =back
 
@@ -6,7 +6,7 @@ package Catalyst::Manual;
 use strict;
 use warnings;
 
-our $VERSION = '5.8003';
+our $VERSION = '5.8004';
 
 =head1 NAME
 
@@ -0,0 +1,5 @@
+use Test::More;
+
+use Test::Pod::Coverage 1.04;
+
+all_pod_coverage_ok();
@@ -0,0 +1,4 @@
+use Test::More;
+use Test::Pod 1.14;
+all_pod_files_ok();
+
@@ -1,7 +0,0 @@
-use Test::More;
-
-eval "use Test::Pod::Coverage 1.04";
-plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
-plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD} || -e 'inc/.author';
-
-all_pod_coverage_ok();
@@ -1,7 +0,0 @@
-use Test::More;
-
-eval "use Test::Pod 1.14";
-plan skip_all => 'Test::Pod 1.14 required' if $@;
-plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD} || -e 'inc/.author';
-
-all_pod_files_ok();